diff --git a/bin/check-requirements.c b/bin/check-requirements.c
new file mode 100644
index 0000000000000000000000000000000000000000..a28c252106187ad2995d8f63cbac8e960d5093bb
--- /dev/null
+++ b/bin/check-requirements.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright © 2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Perform some checks to ensure that the Steam client requirements are met.
+ * Output a human-readable message on stdout if the current system does not
+ * meet every requirement.
+ */
+
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <steam-runtime-tools/utils-internal.h>
+
+#define X86_FEATURES_REQUIRED (SRT_X86_FEATURE_X86_64 \
+                               | SRT_X86_FEATURE_CMPXCHG16B \
+                               | SRT_X86_FEATURE_SSE3)
+
+enum
+{
+  OPTION_HELP = 1,
+  OPTION_VERSION,
+};
+
+struct option long_options[] =
+{
+    { "version", no_argument, NULL, OPTION_VERSION },
+    { "help", no_argument, NULL, OPTION_HELP },
+    { NULL, 0, NULL, 0 }
+};
+
+static void usage (int code) __attribute__((__noreturn__));
+
+/*
+ * Print usage information and exit with status @code.
+ */
+static void
+usage (int code)
+{
+  FILE *fp;
+
+  if (code == 0)
+    fp = stdout;
+  else
+    fp = stderr;
+
+  fprintf (fp, "Usage: %s [OPTIONS]\n",
+           program_invocation_short_name);
+  exit (code);
+}
+
+static FILE *
+divert_stdout_to_stderr (GError **error)
+{
+  int original_stdout_fd;
+  FILE *original_stdout;
+
+  /* Duplicate the original stdout so that we still have a way to write
+   * machine-readable output. */
+  original_stdout_fd = dup (STDOUT_FILENO);
+
+  if (original_stdout_fd < 0)
+    {
+      int saved_errno = errno;
+
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+                   "Unable to duplicate fd %d: %s",
+                   STDOUT_FILENO, g_strerror (saved_errno));
+      return NULL;
+    }
+
+  /* If something like g_debug writes to stdout, make it come out of
+   * our original stderr. */
+  if (dup2 (STDERR_FILENO, STDOUT_FILENO) != STDOUT_FILENO)
+    {
+      int saved_errno = errno;
+
+      close (original_stdout_fd);
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+                   "Unable to make fd %d a copy of fd %d: %s",
+                   STDOUT_FILENO, STDERR_FILENO, g_strerror (saved_errno));
+      return NULL;
+    }
+
+  /* original_stdout takes ownership of original_stdout_fd on success */
+  original_stdout = fdopen (original_stdout_fd, "w");
+
+  if (original_stdout == NULL)
+    {
+      int saved_errno = errno;
+
+      close (original_stdout_fd);
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+                   "Unable to create a stdio wrapper for fd %d: %s",
+                   original_stdout_fd, g_strerror (saved_errno));
+      return NULL;
+    }
+
+  return original_stdout;
+}
+
+static gboolean
+check_x86_features (SrtX86FeatureFlags features)
+{
+  return ((features & X86_FEATURES_REQUIRED) == X86_FEATURES_REQUIRED);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  FILE *original_stdout = NULL;
+  GError *error = NULL;
+  SrtSystemInfo *info;
+  SrtX86FeatureFlags x86_features = SRT_X86_FEATURE_NONE;
+  const gchar *output = NULL;
+  gchar *version = NULL;
+  int opt;
+  int exit_code = EXIT_SUCCESS;
+
+  while ((opt = getopt_long (argc, argv, "", long_options, NULL)) != -1)
+    {
+      switch (opt)
+        {
+          case OPTION_VERSION:
+            /* Output version number as YAML for machine-readability,
+             * inspired by `ostree --version` and `docker version` */
+            printf (
+                "%s:\n"
+                " Package: steam-runtime-tools\n"
+                " Version: %s\n",
+                argv[0], VERSION);
+            return EXIT_SUCCESS;
+
+          case OPTION_HELP:
+            usage (0);
+            break;
+
+          case '?':
+          default:
+            usage (EX_USAGE);
+            break;  /* not reached */
+        }
+    }
+
+  if (optind != argc)
+    usage (EX_USAGE);
+
+  /* stdout is reserved for machine-readable output, so avoid having
+   * things like g_debug() pollute it. */
+  original_stdout = divert_stdout_to_stderr (&error);
+
+  if (original_stdout == NULL)
+    {
+      g_warning ("%s", error->message);
+      g_clear_error (&error);
+      return EXIT_FAILURE;
+    }
+
+  _srt_unblock_signals ();
+
+  info = srt_system_info_new (NULL);
+
+  /* This might be required for unit testing */
+  srt_system_info_set_sysroot (info, g_getenv ("SRT_TEST_SYSROOT"));
+
+  x86_features = srt_system_info_get_x86_features (info);
+  if (!check_x86_features (x86_features))
+    {
+      output = "Sorry, this computer's CPU is too old to run Steam.\n"
+               "\nSteam requires at least an Intel Pentium 4 or AMD Opteron, with the following features:\n"
+               "\t- x86-64 (AMD64) instruction set (lm in /proc/cpuinfo flags)\n"
+               "\t- CMPXCHG16B instruction support (cx16 in /proc/cpuinfo flags)\n"
+               "\t- SSE3 instruction support (pni in /proc/cpuinfo flags)\n";
+      exit_code = EX_OSERR;
+      goto out;
+    }
+
+out:
+  if (output != NULL)
+    {
+      if (fputs (output, original_stdout) < 0)
+        g_warning ("Unable to write output: %s", g_strerror (errno));
+
+      if (fputs ("\n", original_stdout) < 0)
+        g_warning ("Unable to write final newline: %s", g_strerror (errno));
+    }
+
+  if (fclose (original_stdout) != 0)
+    g_warning ("Unable to close stdout: %s", g_strerror (errno));
+
+  g_object_unref (info);
+  g_free (version);
+
+  return exit_code;
+}
diff --git a/bin/check-requirements.md b/bin/check-requirements.md
new file mode 100644
index 0000000000000000000000000000000000000000..2894e8356c6d28594a020a1a7886513dea086e79
--- /dev/null
+++ b/bin/check-requirements.md
@@ -0,0 +1,43 @@
+---
+title: steam-runtime-check-requirements
+section: 1
+...
+
+# NAME
+
+steam-runtime-check-requirements - perform checks to ensure that the Steam client requirements are met
+
+# SYNOPSIS
+
+**steam-runtime-check-requirements**
+
+# DESCRIPTION
+
+# OPTIONS
+
+**--version**
+:   Instead of performing the checks, write in output the version number as
+    YAML.
+
+# OUTPUT
+
+If all the Steam client requirements are met the output will be empty.
+
+Otherwise if some of the checks fails, the output will have a human-readable
+message explaining what failed.
+
+
+# EXIT STATUS
+
+0
+:   **steam-runtime-check-requirements** ran successfully and all the Steam
+    client requirements are met.
+
+71
+:   At least one of the requirements is not met. In this case the exit status
+    will be 71 (EX_OSERR).
+
+Other Nonzero
+:   An error occurred.
+
+<!-- vim:set sw=4 sts=4 et: -->
diff --git a/bin/meson.build b/bin/meson.build
index c99713ded380b34a9537829a17e0d474f3e1fc41..1e7d45f37e0ef3e112eda0ef71600fd1c17976e2 100644
--- a/bin/meson.build
+++ b/bin/meson.build
@@ -32,23 +32,39 @@ executable(
   install_rpath : bin_rpath,
 )
 
+executable(
+  'steam-runtime-check-requirements',
+  'check-requirements.c',
+  dependencies : [glib, gobject, libsteamrt_dep],
+  install : true,
+  # Use the adjacent libsteam-runtime-tools and json-glib, ignoring
+  # LD_LIBRARY_PATH even if set
+  build_rpath : bin_rpath,
+  install_rpath : bin_rpath,
+)
+
 if get_option('man')
-  custom_target(
-    'steam-runtime-system-info.1',
-    build_by_default : true,
-    command : [
-      pandoc,
-      '-s',
-      '-o', '@OUTPUT@',
-      '-f', pandoc_markdown_nosmart,
-      '-t', 'man',
-      '@INPUT@',
-    ],
-    input : 'system-info.md',
-    output : 'steam-runtime-system-info.1',
-    install : true,
-    install_dir : join_paths(get_option('prefix'), get_option('mandir'), 'man1'),
-  )
+  foreach bin_name : [
+    'check-requirements',
+    'system-info',
+  ]
+    custom_target(
+      'steam-runtime-' + bin_name + '.1',
+      build_by_default : true,
+      command : [
+        pandoc,
+        '-s',
+        '-o', '@OUTPUT@',
+        '-f', pandoc_markdown_nosmart,
+        '-t', 'man',
+        '@INPUT@',
+      ],
+      input : bin_name + '.md',
+      output : 'steam-runtime-' + bin_name + '.1',
+      install : true,
+      install_dir : join_paths(get_option('prefix'), get_option('mandir'), 'man1'),
+    )
+  endforeach
 endif
 
 # vim:set sw=2 sts=2 et:
diff --git a/debian/control b/debian/control
index 6f77178cb0d0e659ead22aa36ef0a896117b87c9..9295e13450333fd08ab0d3c75f5cf575608bccea 100644
--- a/debian/control
+++ b/debian/control
@@ -107,9 +107,10 @@ Description:
  supporting code used by the Steam client to discover system information.
  .
  This package contains symbolic links to libraries depended on by the
- steam-runtime-system-info and libsteam-runtime-tools-0-helpers packages,
- which make it possible to run those tools from an LD_LIBRARY_PATH-style
- Steam Runtime even if the LD_LIBRARY_PATH is not correctly set.
+ steam-runtime-system-info, steam-runtime-check-requirements and
+ libsteam-runtime-tools-0-helpers packages, which make it possible to run
+ those tools from an LD_LIBRARY_PATH-style Steam Runtime even if the
+ LD_LIBRARY_PATH is not correctly set.
 
 Package: libsteam-runtime-tools-0-tests
 Architecture: any
@@ -146,4 +147,5 @@ Description: Steam Runtime utility library - command-line tools
  .
  This package contains the command-line tool steam-runtime-system-info,
  which summarizes everything that the libsteam-runtime-tools library
- can find out.
+ can find out, and steam-runtime-check-requirements, which performs checks
+ to ensure that the Steam client requirements are met.
diff --git a/debian/rules b/debian/rules
index e0bef9f6d0846e19b634b4f8bfc15517cf857e79..34f9df78b0c27d2bc0e23f684ad0bee763634ca9 100755
--- a/debian/rules
+++ b/debian/rules
@@ -91,6 +91,7 @@ override_dh_shlibdeps:
 		-plibsteam-runtime-tools-0-relocatable-libs \
 		-- \
 		-prelocatable \
+		-e$(DESTDIR)/usr/bin/steam-runtime-check-requirements \
 		-e$(DESTDIR)/usr/bin/steam-runtime-system-info \
 		-e$(DESTDIR)/usr/$(pkglibexecdir)/$(DEB_HOST_MULTIARCH)-check-locale \
 		$(NULL)
@@ -108,6 +109,7 @@ override_dh_link:
 		--link-target / \
 		--no-glibc \
 		--provider / \
+		only-dependencies:path:$(DESTDIR)/usr/bin/steam-runtime-check-requirements \
 		only-dependencies:path:$(DESTDIR)/usr/bin/steam-runtime-system-info \
 		only-dependencies:path:$(DESTDIR)/usr/$(pkglibexecdir)/$(DEB_HOST_MULTIARCH)-check-locale \
 		$(NULL)
diff --git a/debian/steam-runtime-tools-bin.install b/debian/steam-runtime-tools-bin.install
index 435718331575e056b06729aad8975514fbe2fdb0..cdf8e8d577461f092dcf422e172dff41fa0f6bb0 100644
--- a/debian/steam-runtime-tools-bin.install
+++ b/debian/steam-runtime-tools-bin.install
@@ -1,2 +1,3 @@
+usr/bin/steam-runtime-check-requirements
 usr/bin/steam-runtime-system-info
 usr/share/man/man1
diff --git a/tests/check-requirements-cli.c b/tests/check-requirements-cli.c
new file mode 100644
index 0000000000000000000000000000000000000000..684bfa87994532bb81d148344214dc02b2b8181f
--- /dev/null
+++ b/tests/check-requirements-cli.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright © 2019-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
+#include <steam-runtime-tools/glib-compat.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <sysexits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "test-utils.h"
+
+static const char *argv0;
+
+typedef struct
+{
+  gchar *srcdir;
+  gchar *builddir;
+} Fixture;
+
+typedef struct
+{
+  int unused;
+} Config;
+
+static void
+setup (Fixture *f,
+       gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+
+  /* For the tests we currently have they are not used yet */
+  f->srcdir = g_strdup (g_getenv ("G_TEST_SRCDIR"));
+  f->builddir = g_strdup (g_getenv ("G_TEST_BUILDDIR"));
+
+  if (f->srcdir == NULL)
+    f->srcdir = g_path_get_dirname (argv0);
+
+  if (f->builddir == NULL)
+    f->builddir = g_path_get_dirname (argv0);
+}
+
+static void
+teardown (Fixture *f,
+          gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+
+  g_free (f->srcdir);
+  g_free (f->builddir);
+}
+
+static void
+test_arguments_validation (Fixture *f,
+                           gconstpointer context)
+{
+  gboolean ret;
+  int exit_status = -1;
+  GError *error = NULL;
+  gchar *output = NULL;
+  gchar *diagnostics = NULL;
+  const gchar *argv[] = { "steam-runtime-check-requirements", NULL, NULL };
+
+  ret = g_spawn_sync (NULL,    /* working directory */
+                      (gchar **) argv,
+                      NULL,    /* envp */
+                      G_SPAWN_SEARCH_PATH,
+                      NULL,    /* child setup */
+                      NULL,    /* user data */
+                      &output,
+                      &diagnostics,
+                      &exit_status,
+                      &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  /* Do not assume the CI workers hardware. So we expect either a success or
+   * an EX_OSERR status */
+  if (exit_status != 0 && WIFEXITED (exit_status))
+    g_assert_cmpint (WEXITSTATUS (exit_status), ==, EX_OSERR);
+  else
+    g_assert_cmpint (exit_status, ==, 0);
+  g_assert_nonnull (output);
+  g_assert_true (g_utf8_validate (output, -1, NULL));
+
+  if (exit_status != 0)
+    g_assert_cmpstr (output, !=, "");
+
+  g_free (output);
+  g_free (diagnostics);
+  argv[1] = "--this-option-is-unsupported";
+  ret = g_spawn_sync (NULL,    /* working directory */
+                      (gchar **) argv,
+                      NULL,    /* envp */
+                      G_SPAWN_SEARCH_PATH,
+                      NULL,    /* child setup */
+                      NULL,    /* user data */
+                      &output,
+                      &diagnostics,
+                      &exit_status,
+                      &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  g_assert_true (WIFEXITED (exit_status));
+  g_assert_cmpint (WEXITSTATUS (exit_status), ==, EX_USAGE);
+  g_assert_nonnull (output);
+  g_assert_cmpstr (output, ==, "");
+  g_assert_true (g_utf8_validate (output, -1, NULL));
+  g_assert_nonnull (diagnostics);
+  g_assert_cmpstr (diagnostics, !=, "");
+  g_assert_true (g_utf8_validate (diagnostics, -1, NULL));
+
+  g_free (output);
+  g_free (diagnostics);
+  argv[1] = "this-argument-is-unsupported";
+  ret = g_spawn_sync (NULL,    /* working directory */
+                      (gchar **) argv,
+                      NULL,    /* envp */
+                      G_SPAWN_SEARCH_PATH,
+                      NULL,    /* child setup */
+                      NULL,    /* user data */
+                      &output,
+                      &diagnostics,
+                      &exit_status,
+                      &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  g_assert_true (WIFEXITED (exit_status));
+  g_assert_cmpint (WEXITSTATUS (exit_status), ==, EX_USAGE);
+  g_assert_nonnull (output);
+  g_assert_cmpstr (output, ==, "");
+  g_assert_true (g_utf8_validate (output, -1, NULL));
+  g_assert_nonnull (diagnostics);
+  g_assert_cmpstr (diagnostics, !=, "");
+  g_assert_true (g_utf8_validate (diagnostics, -1, NULL));
+
+  g_free (output);
+  g_free (diagnostics);
+  g_clear_error (&error);
+}
+
+/*
+ * Test `steam-runtime-check-requirements --help` and `--version`.
+ */
+static void
+test_help_and_version (Fixture *f,
+                       gconstpointer context)
+{
+  gboolean ret;
+  int exit_status = -1;
+  GError *error = NULL;
+  gchar *output = NULL;
+  gchar *diagnostics = NULL;
+  const gchar *argv[] = {
+      "env",
+      "LC_ALL=C",
+      "steam-runtime-check-requirements",
+      "--version",
+      NULL
+  };
+
+  ret = g_spawn_sync (NULL,    /* working directory */
+                      (gchar **) argv,
+                      NULL,    /* envp */
+                      G_SPAWN_SEARCH_PATH,
+                      NULL,    /* child setup */
+                      NULL,    /* user data */
+                      &output,
+                      &diagnostics,
+                      &exit_status,
+                      &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_nonnull (output);
+  g_assert_cmpstr (output, !=, "");
+  g_assert_true (g_utf8_validate (output, -1, NULL));
+  g_assert_nonnull (diagnostics);
+
+  g_assert_nonnull (strstr (output, VERSION));
+
+  g_free (output);
+  g_free (diagnostics);
+  g_clear_error (&error);
+
+  argv[3] = "--help";
+
+  ret = g_spawn_sync (NULL,    /* working directory */
+                      (gchar **) argv,
+                      NULL,    /* envp */
+                      G_SPAWN_SEARCH_PATH,
+                      NULL,    /* child setup */
+                      NULL,    /* user data */
+                      &output,
+                      &diagnostics,
+                      &exit_status,
+                      &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_nonnull (output);
+  g_assert_cmpstr (output, !=, "");
+  g_assert_true (g_utf8_validate (output, -1, NULL));
+  g_assert_nonnull (diagnostics);
+
+  g_assert_nonnull (strstr (output, "OPTIONS"));
+
+  g_free (output);
+  g_free (diagnostics);
+  g_clear_error (&error);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  argv0 = argv[0];
+
+  g_test_init (&argc, &argv, NULL);
+  g_test_add ("/check-requirements-cli/arguments_validation", Fixture, NULL,
+              setup, test_arguments_validation, teardown);
+  g_test_add ("/check-requirements-cli/help-and-version", Fixture, NULL,
+              setup, test_help_and_version, teardown);
+
+  return g_test_run ();
+}
diff --git a/tests/meson.build b/tests/meson.build
index 1e787097d443ed5acee0cb23a82ae35f050bb866..7e2e59a8d09f19a78c2b6fc39e60773d4b923232 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -29,6 +29,7 @@ test_env.prepend('PATH', join_paths(meson.current_build_dir(), '..', 'bin'))
 
 tests = [
   'architecture',
+  'check-requirements-cli',
   'desktop-entry',
   'graphics',
   'library',