diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 4b8ea81..86b7896 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -493,30 +493,54 @@ void igt_kselftest_fini(struct igt_kselftest *tst)
 	kmod_module_unref(tst->kmod);
 }
 
+static void mocklist_mark_entry(struct igt_kselftest_mockentry *mocklist,
+				const char *name)
+{
+	struct igt_kselftest_mockentry *me;
+
+	for (me = mocklist; me->name != NULL; ++me) {
+		if (!strcmp(me->name, name)) {
+			me->do_mock = false;
+			return;
+		}
+	}
+}
+
 void igt_kselftests(const char *module_name,
 		    const char *options,
 		    const char *result,
-		    const char *filter)
+		    const char *filter,
+		    struct igt_kselftest_mockentry *mocklist)
 {
 	struct igt_kselftest tst;
 	IGT_LIST(tests);
 	struct igt_kselftest_list *tl, *tn;
+	struct igt_kselftest_mockentry *me;
 
-	igt_require(igt_kselftest_init(&tst, module_name) == 0);
-	igt_fixture
-		igt_require(igt_kselftest_begin(&tst) == 0);
+	if (igt_kselftest_init(&tst, module_name) == 0) {
+		igt_fixture
+			igt_require(igt_kselftest_begin(&tst) == 0);
 
-	igt_kselftest_get_tests(tst.kmod, filter, &tests);
-	igt_list_for_each_safe(tl, tn, &tests, link) {
-		igt_subtest_f("%s", tl->name)
-			igt_kselftest_execute(&tst, tl, options, result);
-		free(tl);
-	}
+		igt_kselftest_get_tests(tst.kmod, filter, &tests);
+		igt_list_for_each_safe(tl, tn, &tests, link) {
+			igt_subtest_f("%s", tl->name)
+				igt_kselftest_execute(&tst, tl, options, result);
+			mocklist_mark_entry(mocklist, tl->name);
+			free(tl);
+		}
 
-	igt_fixture {
-		igt_kselftest_end(&tst);
-		igt_require(!igt_list_empty(&tests));
+		igt_fixture {
+			igt_kselftest_end(&tst);
+			igt_require(!igt_list_empty(&tests));
+		}
+
+		igt_kselftest_fini(&tst);
 	}
 
-	igt_kselftest_fini(&tst);
+	/* Expose subtests for anything the above didn't already generate. */
+	for (me = mocklist; me->name != NULL; ++me) {
+		if (me->do_mock)
+			igt_subtest(me->name)
+				igt_skip("Kernel selftest not present");
+	}
 }
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
index 10cd3a2..d49e9d4 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -35,10 +35,16 @@ int igt_kmod_unload(const char *mod_name, unsigned int flags);
 int igt_i915_driver_load(const char *opts);
 int igt_i915_driver_unload(void);
 
+struct igt_kselftest_mockentry {
+	const char *name;
+	bool do_mock;
+};
+
 void igt_kselftests(const char *module_name,
 		    const char *module_options,
 		    const char *result_option,
-		    const char *filter);
+		    const char *filter,
+		    struct igt_kselftest_mockentry* mocklist);
 
 struct igt_kselftest {
 	struct kmod_module *kmod;
diff --git a/tests/drm_mm.c b/tests/drm_mm.c
index 2052b11..2a3212e 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -28,5 +28,20 @@ IGT_TEST_DESCRIPTION("Basic sanity check of DRM's range manager (struct drm_mm)"
 
 igt_main
 {
-	igt_kselftests("test-drm_mm", NULL, NULL, NULL);
+	/*
+	 * Set of subtest names that are always exposed by IGT,
+	 * regardless of the running kernel's capabilities. Selftests
+	 * that the kernel has but are not on these lists are also
+	 * exposed. This is a known intentional violation of the
+	 * general rule that subtest enumeration must not change
+	 * depending on the runtime environment.
+	 */
+	struct igt_kselftest_mockentry drm_mm_testlist[] = {
+#define selftest(n, x) { .name = #n, .do_mock = true },
+#include "drm_mm_selftests.h"
+#undef selftest
+		{ NULL, false }
+	};
+
+	igt_kselftests("test-drm_mm", NULL, NULL, NULL, drm_mm_testlist);
 }
diff --git a/tests/drv_selftest.c b/tests/drv_selftest.c
index 96dd8bf..eb34fdf 100644
--- a/tests/drv_selftest.c
+++ b/tests/drv_selftest.c
@@ -28,6 +28,27 @@ IGT_TEST_DESCRIPTION("Basic unit tests for i915.ko");
 
 igt_main
 {
-	igt_kselftests("i915", "mock_selftests=-1", NULL, "mock");
-	igt_kselftests("i915", "live_selftests=-1", "live_selftests", "live");
+	/*
+	 * Set of subtest names that are always exposed by IGT,
+	 * regardless of the running kernel's capabilities. Selftests
+	 * that the kernel has but are not on these lists are also
+	 * exposed. This is a known intentional violation of the
+	 * general rule that subtest enumeration must not change
+	 * depending on the runtime environment.
+	 */
+	struct igt_kselftest_mockentry i915_mock_testlist[] = {
+#define selftest(n, x) { .name = #n, .do_mock = true },
+#include "i915_mock_selftests.h"
+#undef selftest
+		{ NULL, false }
+	};
+	struct igt_kselftest_mockentry i915_live_testlist[] = {
+#define selftest(n, x) { .name = #n, .do_mock = true },
+#include "i915_mock_selftests.h"
+#undef selftest
+		{ NULL, false }
+	};
+
+	igt_kselftests("i915", "mock_selftests=-1", NULL, "mock", i915_mock_testlist);
+	igt_kselftests("i915", "live_selftests=-1", "live_selftests", "live", i915_live_testlist);
 }
