diff --git a/.gitignore b/.gitignore
index 329b876b0cb8c836d0fb24568df2d53c61c97aa6..54314a50d115608f9b2255a044fb9a56ce97bac6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
 /libcapsule_*.tar.[gx]z
 /pressure-vessel-[0-9]*.tar.gz
 /relocatable-install/
+/subprojects/steam-runtime-tools/
diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md
index aab21266a4b48e21ad136e0fd7def75e64c02cb3..e4c524bc04063a9621c50f6779a535a16feb0f22 100644
--- a/THIRD-PARTY.md
+++ b/THIRD-PARTY.md
@@ -10,11 +10,17 @@ same place as pressure-vessel, or from
 pressure-vessel incorporates code from GNOME libglnx, variously licensed
 under [LGPL-2.0-or-later][] and [LGPL-2.1-or-later][].
 Complete source code can be obtained from the same place as
-pressure-vessel.
+pressure-vessel, or from <http://repo.steampowered.com/steamrt/>.
 
 pressure-vessel incorporates code from Flatpak, licensed under
 [LGPL-2.1-or-later][]. Complete source code can be obtained from the
-same place as pressure-vessel.
+same place as pressure-vessel, or from
+<http://repo.steampowered.com/steamrt/>.
+
+pressure-vessel includes the steam-runtime-tools library and utilities,
+which are licensed under the [MIT][] license. See steam-runtime-tools.txt.
+Complete source code can be obtained from the same place as pressure-vessel,
+or from <http://repo.steampowered.com/steamrt/>.
 
 Binary releases of pressure-vessel include the following third-party
 programs and libraries:
@@ -47,6 +53,9 @@ programs and libraries:
 
 - libz.so.1 from zlib: [Zlib][] license. See zlib.txt.
 
+- libjson-glib-1.0.so.0 from json-glib: [LGPL-2.0-or-later][]. See
+  json-glib.txt.
+
 Complete source code can be obtained from the same place as
 pressure-vessel, or from <http://repo.steampowered.com/steamrt/>.
 
diff --git a/build-relocatable-install.py b/build-relocatable-install.py
index cf86be7c5a03069468bfefe48d2bedfda3f14dcd..8bd52e776b120efcec360df4fefa9be7fe1a4a5f 100755
--- a/build-relocatable-install.py
+++ b/build-relocatable-install.py
@@ -78,11 +78,13 @@ ARCHS = [
 DEPENDENCIES = {
     'libcapsule-tools-relocatable': 'libcapsule',
     'libelf1': 'elfutils',
+    'libsteam-runtime-tools-0-helpers': 'steam-runtime-tools',
     'zlib1g': 'zlib',
 }
 # program to install => binary package
 WRAPPED_PROGRAMS = {
     'bwrap': 'bubblewrap',
+    'steam-runtime-system-info': 'steam-runtime-tools-bin',
 }
 PRIMARY_ARCH_DEPENDENCIES = {
     'bubblewrap': 'bubblewrap',
@@ -90,10 +92,12 @@ PRIMARY_ARCH_DEPENDENCIES = {
     'libcap2': 'libcap2',
     'libffi6': 'libffi',
     'libglib2.0-0': 'glib2.0',
+    'libjson-glib-1.0-0': 'json-glib',
     'libmount1': 'util-linux',
     'libpcre3': 'pcre3',
-    'libxau6': 'libxau',
     'libselinux1': 'libselinux',
+    'libsteam-runtime-tools-0-0': 'steam-runtime-tools',
+    'libxau6': 'libxau',
 }
 SCRIPTS = [
     'pressure-vessel-locale-gen',
@@ -233,6 +237,7 @@ def main():
             raise RuntimeError('--output directory must not already exist')
 
         os.makedirs(os.path.join(installation, 'bin'), exist_ok=True)
+        os.makedirs(os.path.join(installation, 'libexec'), exist_ok=True)
         os.makedirs(os.path.join(installation, 'metadata'), exist_ok=True)
 
         for arch in ARCHS:
@@ -291,6 +296,35 @@ def main():
                     os.path.join(installation, 'bin'),
                 )
 
+            path = '/usr/libexec/steam-runtime-tools-0'
+
+            if not os.path.exists(path):
+                package = 'libsteam-runtime-tools-0-helpers'
+                v_check_call([
+                    'apt-get',
+                    'download',
+                    package + ':' + arch.name,
+                ], cwd=tmpdir)
+                v_check_call(
+                    'dpkg-deb -X {}_*_{}.deb build-relocatable'.format(
+                        quote(package),
+                        quote(arch.name),
+                    ),
+                    cwd=tmpdir,
+                    shell=True,
+                )
+                path = '{}/build-relocatable/{}'.format(tmpdir, path)
+
+            for tool in glob.glob(os.path.join(path, arch.multiarch + '-*')):
+                install_exe(
+                    tool,
+                    os.path.join(
+                        installation,
+                        'libexec',
+                        'steam-runtime-tools-0',
+                    ),
+                )
+
         primary_architecture = subprocess.check_output([
             'dpkg', '--print-architecture',
         ]).decode('utf-8').strip()
@@ -329,8 +363,10 @@ def main():
                     'soname:libXau.so.6',
                     'soname:libcap.so.2',
                     'soname:libgio-2.0.so.0',
+                    'soname:libjson-glib-1.0.so.0',
                     'soname:libpcre.so.3',
                     'soname:libselinux.so.1',
+                    'soname:libsteam-runtime-tools-0.so.0',
                 ])
 
             for so in glob.glob(
diff --git a/ci/Dockerfile.in b/ci/Dockerfile.in
index 86e6adba22d4026222dc143f93f77f0b3b2c942c..29def092ee4b20e919879837633dcc094771a25a 100644
--- a/ci/Dockerfile.in
+++ b/ci/Dockerfile.in
@@ -17,9 +17,13 @@ apt-get -y install \
     libmount1 \
     libpcre3 \
     libselinux1 \
+    libsteam-runtime-tools-0-dev \
+    libsteam-runtime-tools-0-helpers:amd64 \
+    libsteam-runtime-tools-0-helpers:i386 \
     libxau6 \
     locales \
     pandoc \
+    steam-runtime-tools-bin \
     zlib1g:amd64 \
     zlib1g:i386 \
     ${NULL+}
diff --git a/debian/control b/debian/control
index 8d88b32de8ef242d0b95b1bf406ea832941f6412..4db9d42c50126e90e3d3119ac242cdf7a2f9787a 100644
--- a/debian/control
+++ b/debian/control
@@ -6,6 +6,7 @@ Standards-Version: 4.4.0
 Build-Depends:
  debhelper (>= 9),
  libglib2.0-dev,
+ libsteam-runtime-tools-0-dev (>= 0.20190926.0~),
  libxau-dev,
  locales <!nocheck> | locales-all <!nocheck>,
  meson,
@@ -22,6 +23,7 @@ Multi-Arch: foreign
 Depends:
  bubblewrap,
  libcapsule-tools-relocatable,
+ steam-runtime-tools-bin,
  ${misc:Depends},
  ${shlibs:Depends},
 Recommends:
@@ -37,6 +39,7 @@ Architecture: amd64
 Multi-Arch: foreign
 Depends:
  libcapsule-tools-relocatable,
+ libsteam-runtime-tools-0-helpers,
  ${misc:Depends},
  ${shlibs:Depends},
 Description: Steam container launcher - cross-architecture dependencies
@@ -49,6 +52,7 @@ Architecture: i386
 Multi-Arch: foreign
 Depends:
  libcapsule-tools-relocatable,
+ libsteam-runtime-tools-0-helpers,
  ${misc:Depends},
  ${shlibs:Depends},
 Description: Steam container launcher - cross-architecture dependencies
diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
index 430e49fcff1797fa9288e6ee73a505180b7e700c..4ff147849a8587c9d51508af9c8c019547294a24 100644
--- a/debian/gitlab-ci.yml
+++ b/debian/gitlab-ci.yml
@@ -29,6 +29,9 @@ variables:
     # Set non-empty to allow
     CI_ALLOW_MISSING_SOURCES: ''
 
+    STEAM_RUNTIME_TOOLS_GIT_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.steamos.cloud/steam/steam-runtime-tools.git
+    STEAM_RUNTIME_TOOLS_GIT_BRANCH: master
+
 build:
     variables:
         BUILD_IMAGE: docker.internal.steamos.cloud/steamos/package-builder:buster
@@ -40,11 +43,10 @@ build:devel:
         - |
             set -eux
 
-            apt-get -y --no-install-recommends install \
-            libglib2.0-dev \
-            libxau-dev \
-            meson \
-            ${NULL+}
+            git clone \
+            -b${STEAM_RUNTIME_TOOLS_GIT_BRANCH} \
+            ${STEAM_RUNTIME_TOOLS_GIT_REPO} \
+            subprojects/steam-runtime-tools
 
             meson _build
             ninja -C _build
@@ -81,9 +83,13 @@ build:scout:
             libcapsule0 \
             libcapsule-tools-relocatable:amd64 \
             libcapsule-tools-relocatable:i386 \
+            libsteam-runtime-tools-0-dev \
+            libsteam-runtime-tools-0-helpers:amd64 \
+            libsteam-runtime-tools-0-helpers:i386 \
             libglib2.0-dev \
             libxau-dev \
             meson \
+            steam-runtime-tools-bin
             ${NULL+}
 
             meson \
diff --git a/debian/tests/relocatable-install b/debian/tests/relocatable-install
index 5bd50727a8e23285290c36ecbeff6aba509b3551..5a623a1dfe3ace957baf87c3ebcb4b28d0e78f86 100755
--- a/debian/tests/relocatable-install
+++ b/debian/tests/relocatable-install
@@ -4,9 +4,15 @@ set -eux
 
 dpkg --add-architecture amd64
 dpkg --add-architecture i386
+apt-get -y update
 apt-get -y install \
     libcapsule-tools-relocatable:amd64 \
     libcapsule-tools-relocatable:i386 \
+    libsteam-runtime-tools-0-0:amd64 \
+    libsteam-runtime-tools-0-0:i386 \
+    libsteam-runtime-tools-0-helpers:amd64 \
+    libsteam-runtime-tools-0-helpers:i386 \
+    steam-runtime-tools-bin \
     ${NULL+}
 
 /usr/lib/pressure-vessel/relocatable/bin/pressure-vessel-build-relocatable-install \
diff --git a/meson.build b/meson.build
index 295cae89abd3670b58e29f2bcbf18e1610bf5d79..30d2004f3d60e404d53b3579ddfc3af6faada974 100644
--- a/meson.build
+++ b/meson.build
@@ -177,6 +177,12 @@ executable(
     '-Wno-unused-local-typedefs',
   ],
   dependencies : [
+    dependency(
+      'steam-runtime-tools-0',
+      required : true,
+      fallback : ['steam-runtime-tools', 'libsteamrt_dep'],
+      default_options : ['gtk_doc=false'],
+    ),
     dependency('gio-unix-2.0', required : true),
     dependency('xau', required : true),
     subproject('libglnx').get_variable('libglnx_dep'),
diff --git a/src/wrap.c b/src/wrap.c
index a621b73653e00e2ccb0eb60751d5046945046ae1..d40ae0e9bf47cdd18fa2a198df1a081f4f0dd357 100644
--- a/src/wrap.c
+++ b/src/wrap.c
@@ -33,10 +33,14 @@
 #include <stdlib.h>
 #include <sysexits.h>
 
+/* Include these before steam-runtime-tools.h so that their backport of
+ * G_DEFINE_AUTOPTR_CLEANUP_FUNC will be visible to it */
+#include "glib-backports.h"
 #include "libglnx.h"
 
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
 #include "bwrap.h"
-#include "glib-backports.h"
 #include "flatpak-bwrap-private.h"
 #include "flatpak-run-private.h"
 #include "flatpak-utils-private.h"
@@ -450,6 +454,193 @@ ensure_locales (gboolean on_host,
     }
 }
 
+typedef enum
+{
+  ICD_KIND_NONEXISTENT,
+  ICD_KIND_ABSOLUTE,
+  ICD_KIND_SONAME
+} IcdKind;
+
+typedef struct
+{
+  /* (type SrtEglIcd) or (type SrtVulkanIcd) */
+  gpointer icd;
+  gchar *resolved_library;
+  /* Last entry is always NONEXISTENT */
+  IcdKind kinds[G_N_ELEMENTS (multiarch_tuples)];
+  /* Last entry is always NULL */
+  gchar *paths_in_container[G_N_ELEMENTS (multiarch_tuples)];
+} IcdDetails;
+
+static IcdDetails *
+icd_details_new (gpointer icd)
+{
+  IcdDetails *self;
+  gsize i;
+
+  g_return_val_if_fail (G_IS_OBJECT (icd), NULL);
+  g_return_val_if_fail (SRT_IS_EGL_ICD (icd) || SRT_IS_VULKAN_ICD (icd),
+                        NULL);
+
+  self = g_slice_new0 (IcdDetails);
+  self->icd = g_object_ref (icd);
+  self->resolved_library = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    {
+      self->kinds[i] = ICD_KIND_NONEXISTENT;
+      self->paths_in_container[i] = NULL;
+    }
+
+  return self;
+}
+
+static void
+icd_details_free (IcdDetails *self)
+{
+  gsize i;
+
+  g_object_unref (self->icd);
+  g_free (self->resolved_library);
+
+  for (i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    g_free (self->paths_in_container[i]);
+
+  g_slice_free (IcdDetails, self);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (IcdDetails, icd_details_free)
+
+static gboolean
+bind_icd (gsize multiarch_index,
+          gsize sequence_number,
+          const char *tool_path,
+          FlatpakBwrap *mount_runtime_on_scratch,
+          const char *scratch,
+          const char *libdir_on_host,
+          const char *libdir_in_container,
+          const char *subdir,
+          IcdDetails *details,
+          GError **error)
+{
+  static const char options[] = "if-exists:if-same-abi";
+  g_autofree gchar *on_host = NULL;
+  g_autofree gchar *pattern = NULL;
+  g_autofree gchar *dependency_pattern = NULL;
+  g_autofree gchar *seq_str = NULL;
+  const char *mode;
+  g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
+
+  g_return_val_if_fail (tool_path != NULL, FALSE);
+  g_return_val_if_fail (mount_runtime_on_scratch != NULL, FALSE);
+  g_return_val_if_fail (mount_runtime_on_scratch->fds == NULL
+                        || mount_runtime_on_scratch->fds->len == 0,
+                        FALSE);
+  g_return_val_if_fail (scratch != NULL, FALSE);
+  g_return_val_if_fail (libdir_on_host != NULL, FALSE);
+  g_return_val_if_fail (subdir != NULL, FALSE);
+  g_return_val_if_fail (multiarch_index < G_N_ELEMENTS (multiarch_tuples) - 1,
+                        FALSE);
+  g_return_val_if_fail (details != NULL, FALSE);
+  g_return_val_if_fail (details->resolved_library != NULL, FALSE);
+  g_return_val_if_fail (details->kinds[multiarch_index] == ICD_KIND_NONEXISTENT,
+                        FALSE);
+  g_return_val_if_fail (details->paths_in_container[multiarch_index] == NULL,
+                        FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (g_path_is_absolute (details->resolved_library))
+    {
+      details->kinds[multiarch_index] = ICD_KIND_ABSOLUTE;
+      mode = "path";
+
+      /* Because the ICDs might have collisions among their
+       * basenames (might differ only by directory), we put each
+       * in its own numbered directory. */
+      seq_str = g_strdup_printf ("%" G_GSIZE_FORMAT, sequence_number);
+      on_host = g_build_filename (libdir_on_host, subdir, seq_str, NULL);
+
+      g_debug ("Ensuring %s exists", on_host);
+
+      if (g_mkdir_with_parents (on_host, 0700) != 0)
+        return glnx_throw_errno_prefix (error, "Unable to create %s", on_host);
+    }
+  else
+    {
+      /* ICDs in the default search path by definition can't collide:
+       * one of them is the first one we find, and we use that one. */
+      details->kinds[multiarch_index] = ICD_KIND_SONAME;
+      mode = "soname";
+    }
+
+  pattern = g_strdup_printf ("no-dependencies:even-if-older:%s:%s:%s",
+                             options, mode, details->resolved_library);
+  dependency_pattern = g_strdup_printf ("only-dependencies:%s:%s:%s",
+                                        options, mode, details->resolved_library);
+
+  temp_bwrap = flatpak_bwrap_new (NULL);
+  flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
+  flatpak_bwrap_add_args (temp_bwrap,
+                          tool_path,
+                          "--container", scratch,
+                          "--link-target", "/run/host",
+                          "--dest", on_host == NULL ? libdir_on_host : on_host,
+                          "--provider", "/",
+                          pattern,
+                          NULL);
+  flatpak_bwrap_finish (temp_bwrap);
+
+  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+    return FALSE;
+
+  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+  if (on_host != NULL)
+    {
+      /* Try to remove the directory we created. If it succeeds, then we
+       * can optimize slightly by not capturing the dependencies: there's
+       * no point, because we know we didn't create a symlink to the ICD
+       * itself. (It must have been nonexistent or for a different ABI.) */
+      if (g_rmdir (on_host) == 0)
+        {
+          details->kinds[multiarch_index] = ICD_KIND_NONEXISTENT;
+          return TRUE;
+        }
+    }
+
+  temp_bwrap = flatpak_bwrap_new (NULL);
+  g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
+                  || mount_runtime_on_scratch->fds->len == 0);
+  flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
+  flatpak_bwrap_add_args (temp_bwrap,
+                          tool_path,
+                          "--container", scratch,
+                          "--link-target", "/run/host",
+                          "--dest", libdir_on_host,
+                          "--provider", "/",
+                          dependency_pattern,
+                          NULL);
+  flatpak_bwrap_finish (temp_bwrap);
+
+  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+    return FALSE;
+
+  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+  if (details->kinds[multiarch_index] == ICD_KIND_ABSOLUTE)
+    {
+      g_assert (seq_str != NULL);
+      g_assert (on_host != NULL);
+      details->paths_in_container[multiarch_index] = g_build_filename (libdir_in_container,
+                                                                       subdir,
+                                                                       seq_str,
+                                                                       glnx_basename (details->resolved_library),
+                                                                       NULL);
+    }
+
+  return TRUE;
+}
+
 static gboolean
 bind_runtime (FlatpakBwrap *bwrap,
               const char *tools_dir,
@@ -484,10 +675,21 @@ bind_runtime (FlatpakBwrap *bwrap,
   gsize i, j;
   const gchar *member;
   g_autoptr(GString) dri_path = g_string_new ("");
+  g_autoptr(GString) egl_path = g_string_new ("");
+  g_autoptr(GString) vulkan_path = g_string_new ("");
   gboolean any_architecture_works = FALSE;
   gboolean any_libc_from_host = FALSE;
   gboolean all_libc_from_host = TRUE;
   g_autofree gchar *localedef = NULL;
+  g_autofree gchar *dir_on_host = NULL;
+  g_autoptr(SrtSystemInfo) system_info = srt_system_info_new (NULL);
+  g_autoptr(SrtObjectList) egl_icds = NULL;
+  g_autoptr(SrtObjectList) vulkan_icds = NULL;
+  g_autoptr(GPtrArray) egl_icd_details = NULL;      /* (element-type IcdDetails) */
+  g_autoptr(GPtrArray) vulkan_icd_details = NULL;   /* (element-type IcdDetails) */
+  guint n_egl_icds;
+  guint n_vulkan_icds;
+  const GList *icd_iter;
 
   g_return_val_if_fail (tools_dir != NULL, FALSE);
   g_return_val_if_fail (runtime != NULL, FALSE);
@@ -583,6 +785,65 @@ bind_runtime (FlatpakBwrap *bwrap,
                             "--ro-bind", "/etc/group", "/etc/group",
                             NULL);
 
+  g_debug ("Enumerating EGL ICDs on host system...");
+  egl_icds = srt_system_info_list_egl_icds (system_info, multiarch_tuples);
+  n_egl_icds = g_list_length (egl_icds);
+
+  egl_icd_details = g_ptr_array_new_full (n_egl_icds,
+                                          (GDestroyNotify) G_CALLBACK (icd_details_free));
+
+  for (icd_iter = egl_icds, j = 0;
+       icd_iter != NULL;
+       icd_iter = icd_iter->next, j++)
+    {
+      SrtEglIcd *icd = icd_iter->data;
+      const gchar *path = srt_egl_icd_get_json_path (icd);
+      GError *local_error = NULL;
+
+      if (!srt_egl_icd_check_error (icd, &local_error))
+        {
+          g_debug ("Failed to load EGL ICD #%" G_GSIZE_FORMAT  " from %s: %s",
+                   j, path, local_error->message);
+          g_clear_error (&local_error);
+          continue;
+        }
+
+      g_debug ("EGL ICD #%" G_GSIZE_FORMAT " at %s: %s",
+               j, path, srt_egl_icd_get_library_path (icd));
+
+      g_ptr_array_add (egl_icd_details, icd_details_new (icd));
+    }
+
+  g_debug ("Enumerating Vulkan ICDs on host system...");
+  vulkan_icds = srt_system_info_list_vulkan_icds (system_info,
+                                                  multiarch_tuples);
+  n_vulkan_icds = g_list_length (vulkan_icds);
+
+  vulkan_icd_details = g_ptr_array_new_full (n_vulkan_icds,
+                                             (GDestroyNotify) G_CALLBACK (icd_details_free));
+
+  for (icd_iter = vulkan_icds, j = 0;
+       icd_iter != NULL;
+       icd_iter = icd_iter->next, j++)
+    {
+      SrtVulkanIcd *icd = icd_iter->data;
+      const gchar *path = srt_vulkan_icd_get_json_path (icd);
+      GError *local_error = NULL;
+
+      if (!srt_vulkan_icd_check_error (icd, &local_error))
+        {
+          g_debug ("Failed to load Vulkan ICD #%" G_GSIZE_FORMAT " from %s: %s",
+                   j, path, local_error->message);
+          g_clear_error (&local_error);
+          continue;
+        }
+
+      g_debug ("Vulkan ICD #%" G_GSIZE_FORMAT " at %s: %s",
+               j, path, srt_vulkan_icd_get_library_path (icd));
+
+      g_ptr_array_add (vulkan_icd_details, icd_details_new (icd));
+    }
+
   g_assert (multiarch_tuples[G_N_ELEMENTS (multiarch_tuples) - 1] == NULL);
 
   for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
@@ -666,6 +927,8 @@ bind_runtime (FlatpakBwrap *bwrap,
                          error))
             return FALSE;
 
+          g_debug ("Collecting GLX drivers from host system...");
+
           temp_bwrap = flatpak_bwrap_new (NULL);
           /* mount_runtime_on_scratch can't own any fds, because if it did,
            * flatpak_bwrap_append_bwrap() would steal them. */
@@ -687,6 +950,79 @@ bind_runtime (FlatpakBwrap *bwrap,
 
           g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
 
+          g_debug ("Collecting %s EGL drivers from host system...",
+                   multiarch_tuples[i]);
+
+          for (j = 0; j < egl_icd_details->len; j++)
+            {
+              IcdDetails *details = g_ptr_array_index (egl_icd_details, j);
+              SrtEglIcd *icd = SRT_EGL_ICD (details->icd);
+
+              if (!srt_egl_icd_check_error (icd, NULL))
+                continue;
+
+              details->resolved_library = srt_egl_icd_resolve_library_path (icd);
+              g_assert (details->resolved_library != NULL);
+
+              if (!bind_icd (i,
+                             j,
+                             tool_path,
+                             mount_runtime_on_scratch,
+                             scratch,
+                             libdir_on_host,
+                             libdir_in_container,
+                             "glvnd",
+                             details,
+                             error))
+                return FALSE;
+            }
+
+          g_debug ("Collecting %s Vulkan drivers from host system...",
+                   multiarch_tuples[i]);
+
+          temp_bwrap = flatpak_bwrap_new (NULL);
+          g_warn_if_fail (mount_runtime_on_scratch->fds == NULL
+                          || mount_runtime_on_scratch->fds->len == 0);
+          flatpak_bwrap_append_bwrap (temp_bwrap, mount_runtime_on_scratch);
+          flatpak_bwrap_add_args (temp_bwrap,
+                                  tool_path,
+                                  "--container", scratch,
+                                  "--link-target", "/run/host",
+                                  "--dest", libdir_on_host,
+                                  "--provider", "/",
+                                  "if-exists:if-same-abi:soname:libvulkan.so.1",
+                                  NULL);
+          flatpak_bwrap_finish (temp_bwrap);
+
+          if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+            return FALSE;
+
+          g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+
+          for (j = 0; j < vulkan_icd_details->len; j++)
+            {
+              IcdDetails *details = g_ptr_array_index (vulkan_icd_details, j);
+              SrtVulkanIcd *icd = SRT_VULKAN_ICD (details->icd);
+
+              if (!srt_vulkan_icd_check_error (icd, NULL))
+                continue;
+
+              details->resolved_library = srt_vulkan_icd_resolve_library_path (icd);
+              g_assert (details->resolved_library != NULL);
+
+              if (!bind_icd (i,
+                             j,
+                             tool_path,
+                             mount_runtime_on_scratch,
+                             scratch,
+                             libdir_on_host,
+                             libdir_in_container,
+                             "vulkan",
+                             details,
+                             error))
+                return FALSE;
+            }
+
           libc = g_build_filename (libdir_on_host, "libc.so.6", NULL);
 
           /* If we are going to use the host system's libc6 (likely)
@@ -853,6 +1189,154 @@ bind_runtime (FlatpakBwrap *bwrap,
       g_debug ("Using included locale data from container");
     }
 
+  g_debug ("Setting up EGL ICD JSON...");
+
+  dir_on_host = g_build_filename (overrides,
+                                  "share", "glvnd", "egl_vendor.d", NULL);
+
+  if (g_mkdir_with_parents (dir_on_host, 0700) != 0)
+    {
+      glnx_throw_errno_prefix (error, "Unable to create %s", dir_on_host);
+      return FALSE;
+    }
+
+  for (j = 0; j < egl_icd_details->len; j++)
+    {
+      IcdDetails *details = g_ptr_array_index (egl_icd_details, j);
+      SrtEglIcd *icd = SRT_EGL_ICD (details->icd);
+      gboolean need_host_json = FALSE;
+
+      if (!srt_egl_icd_check_error (icd, NULL))
+        continue;
+
+      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+        {
+          g_assert (i < G_N_ELEMENTS (details->kinds));
+          g_assert (i < G_N_ELEMENTS (details->paths_in_container));
+
+          if (details->kinds[i] == ICD_KIND_ABSOLUTE)
+            {
+              g_autoptr(SrtEglIcd) replacement = NULL;
+              g_autofree gchar *json_on_host = NULL;
+              g_autofree gchar *json_in_container = NULL;
+              g_autofree gchar *json_base = NULL;
+
+              g_assert (details->paths_in_container[i] != NULL);
+
+              json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
+                                           j, multiarch_tuples[i]);
+              json_on_host = g_build_filename (dir_on_host, json_base, NULL);
+              json_in_container = g_build_filename ("/overrides", "share",
+                                                    "glvnd", "egl_vendor.d",
+                                                    json_base, NULL);
+
+              replacement = srt_egl_icd_new_replace_library_path (icd,
+                                                                  details->paths_in_container[i]);
+
+              if (!srt_egl_icd_write_to_file (replacement, json_on_host,
+                                                 error))
+                return FALSE;
+
+              search_path_append (egl_path, json_in_container);
+            }
+          else if (details->kinds[i] == ICD_KIND_SONAME)
+            {
+              need_host_json = TRUE;
+            }
+        }
+
+      if (need_host_json)
+        {
+          g_autofree gchar *json_in_container = NULL;
+          g_autofree gchar *json_base = NULL;
+          const char *json_on_host = srt_egl_icd_get_json_path (icd);
+
+          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", j);
+          json_in_container = g_build_filename ("/overrides", "share",
+                                                "glvnd", "egl_vendor.d",
+                                                json_base, NULL);
+
+          flatpak_bwrap_add_args (bwrap,
+                                  "--ro-bind", json_on_host, json_in_container,
+                                  NULL);
+          search_path_append (egl_path, json_in_container);
+        }
+    }
+
+  g_debug ("Setting up Vulkan ICD JSON...");
+
+  dir_on_host = g_build_filename (overrides,
+                                  "share", "vulkan", "icd.d", NULL);
+
+  if (g_mkdir_with_parents (dir_on_host, 0700) != 0)
+    {
+      glnx_throw_errno_prefix (error, "Unable to create %s", dir_on_host);
+      return FALSE;
+    }
+
+  for (j = 0; j < vulkan_icd_details->len; j++)
+    {
+      IcdDetails *details = g_ptr_array_index (vulkan_icd_details, j);
+      SrtVulkanIcd *icd = SRT_VULKAN_ICD (details->icd);
+      gboolean need_host_json = FALSE;
+
+      if (!srt_vulkan_icd_check_error (icd, NULL))
+        continue;
+
+      for (i = 0; i < G_N_ELEMENTS (multiarch_tuples) - 1; i++)
+        {
+          g_assert (i < G_N_ELEMENTS (details->kinds));
+          g_assert (i < G_N_ELEMENTS (details->paths_in_container));
+
+          if (details->kinds[i] == ICD_KIND_ABSOLUTE)
+            {
+              g_autoptr(SrtVulkanIcd) replacement = NULL;
+              g_autofree gchar *json_on_host = NULL;
+              g_autofree gchar *json_in_container = NULL;
+              g_autofree gchar *json_base = NULL;
+
+              g_assert (details->paths_in_container[i] != NULL);
+
+              json_base = g_strdup_printf ("%" G_GSIZE_FORMAT "-%s.json",
+                                           j, multiarch_tuples[i]);
+              json_on_host = g_build_filename (dir_on_host, json_base, NULL);
+              json_in_container = g_build_filename ("/overrides", "share",
+                                                    "vulkan", "icd.d",
+                                                    json_base, NULL);
+
+              replacement = srt_vulkan_icd_new_replace_library_path (icd,
+                                                                     details->paths_in_container[i]);
+
+              if (!srt_vulkan_icd_write_to_file (replacement, json_on_host,
+                                                 error))
+                return FALSE;
+
+              search_path_append (vulkan_path, json_in_container);
+            }
+          else if (details->kinds[i] == ICD_KIND_SONAME)
+            {
+              need_host_json = TRUE;
+            }
+        }
+
+      if (need_host_json)
+        {
+          g_autofree gchar *json_in_container = NULL;
+          g_autofree gchar *json_base = NULL;
+          const char *json_on_host = srt_vulkan_icd_get_json_path (icd);
+
+          json_base = g_strdup_printf ("%" G_GSIZE_FORMAT ".json", j);
+          json_in_container = g_build_filename ("/overrides", "share",
+                                                "vulkan", "icd.d",
+                                                json_base, NULL);
+
+          flatpak_bwrap_add_args (bwrap,
+                                  "--ro-bind", json_on_host, json_in_container,
+                                  NULL);
+          search_path_append (vulkan_path, json_in_container);
+        }
+    }
+
   if (!pv_bwrap_bind_usr (bwrap, "/", "/run/host", error))
     return FALSE;
 
@@ -867,6 +1351,28 @@ bind_runtime (FlatpakBwrap *bwrap,
                               "--unsetenv", "LIBGL_DRIVERS_PATH",
                               NULL);
 
+  if (egl_path->len != 0)
+      flatpak_bwrap_add_args (bwrap,
+                              "--setenv", "__EGL_VENDOR_LIBRARY_FILENAMES",
+                              egl_path->str, NULL);
+  else
+      flatpak_bwrap_add_args (bwrap,
+                              "--unsetenv", "__EGL_VENDOR_LIBRARY_FILENAMES",
+                              NULL);
+
+  flatpak_bwrap_add_args (bwrap,
+                          "--unsetenv", "__EGL_VENDOR_LIBRARY_DIRS",
+                          NULL);
+
+  if (vulkan_path->len != 0)
+      flatpak_bwrap_add_args (bwrap,
+                              "--setenv", "VK_ICD_FILENAMES",
+                              vulkan_path->str, NULL);
+  else
+      flatpak_bwrap_add_args (bwrap,
+                              "--unsetenv", "VK_ICD_FILENAMES",
+                              NULL);
+
   /* These can add data fds to @bwrap, so they must come last - after
    * other functions stop using @bwrap as a basis for their own bwrap
    * invocations with flatpak_bwrap_append_bwrap().
diff --git a/subprojects/steam-runtime-tools.wrap b/subprojects/steam-runtime-tools.wrap
new file mode 100644
index 0000000000000000000000000000000000000000..f30180ac0896545be6bbb92a3f6a83a1738b9919
--- /dev/null
+++ b/subprojects/steam-runtime-tools.wrap
@@ -0,0 +1,4 @@
+[wrap-git]
+directory = steam-runtime-tools
+url = https://gitlab.steamos.cloud/steam/steam-runtime-tools.git
+revision = head