diff --git a/core/includes/install.inc b/core/includes/install.inc
index 2d246b5c84269eb7c0cbbc3fc7e8b48644c1bdcf..fb0e10777b8e3f61bb126684351c67df0cbd77aa 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -9,7 +9,9 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Database\Database;
 use Drupal\Core\Extension\Dependency;
+use Drupal\Core\Extension\Extension;
 use Drupal\Core\Extension\ExtensionDiscovery;
+use Drupal\Core\Extension\InstallRequirementsInterface;
 use Drupal\Core\Installer\InstallerKernel;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -616,6 +618,8 @@ function drupal_check_profile($profile) {
       if (function_exists($function)) {
         $requirements = array_merge($requirements, $function('install'));
       }
+
+      $requirements = array_merge($requirements, install_check_class_requirements($module_list[$module]));
     }
   }
 
@@ -625,6 +629,9 @@ function drupal_check_profile($profile) {
     $requirements = array_merge($requirements, $function('install'));
   }
 
+  $extension = \Drupal::service('extension.list.profile')->get($profile);
+  $requirements = array_merge($requirements, install_check_class_requirements($extension));
+
   return $requirements;
 }
 
@@ -660,13 +667,16 @@ function drupal_requirements_severity(&$requirements) {
 function drupal_check_module($module) {
   /** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */
   $module_list = \Drupal::service('extension.list.module');
-  $file = DRUPAL_ROOT . '/' . $module_list->getPath($module) . "/$module.install";
+  $extension = $module_list->get($module);
+  $file = \Drupal::root() . '/' . $extension->getPath() . "/$module.install";
   if (is_file($file)) {
     require_once $file;
   }
   // Check requirements
-  $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']);
-  if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
+  $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']) ?? [];
+  $requirements = array_merge($requirements, install_check_class_requirements($extension));
+
+  if (!empty($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
     // Print any error messages
     foreach ($requirements as $requirement) {
       if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
@@ -790,3 +800,41 @@ function install_profile_info($profile, $langcode = 'en') {
   }
   return $cache[$profile][$langcode];
 }
+
+/**
+ * Checks a module or profile requirements.
+ *
+ * See \Drupal\Core\Extension\InstallRequirementsInterface for more information.
+ *
+ * @param \Drupal\Core\Extension $extension
+ *   The extension to check install requirements for.
+ *
+ * @return array
+ *   The requirements.
+ *
+ * @internal
+ */
+function install_check_class_requirements(Extension $extension): array {
+  $extension_path = $extension->getPath();
+  $extension_name = $extension->getName();
+  $dir = \Drupal::root() . "/$extension_path/src/Install/Requirements";
+  $requirements = [];
+  if (is_dir($dir)) {
+    $fileSystemIterator = new FilesystemIterator($dir);
+    foreach ($fileSystemIterator as $fileInfo) {
+      if ($fileInfo->isFile() && $fileInfo->getExtension() === 'php') {
+        $filename = $fileInfo->getFilename();
+        $requirements_path = $dir . '/' . $filename;
+        require_once $requirements_path;
+
+        $namespace = "Drupal\\$extension_name\\Install\\Requirements";
+        $class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
+        if (class_exists($class_name) && class_implements($class_name, InstallRequirementsInterface::class)) {
+          $requirements = $class_name::getRequirements();
+        }
+      }
+    }
+
+  }
+  return $requirements;
+}
diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..ca1ad6afd6736db007e2b0617e5b3692d2619ef9
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\Core\Extension;
+
+/**
+ * Provides method for checking requirements during install time.
+ */
+interface InstallRequirementsInterface {
+
+  /**
+   * Check installation requirements.
+   *
+   * Classes implementing this must be in the Install/Requirements namespace.
+   * For example src/Install/Requirements/ModuleNameRequirements.php.
+   *
+   * During the 'install' phase, modules can for example assert that
+   * library or server versions are available or sufficient.
+   * Note that the installation of a module can happen during installation of
+   * Drupal itself (by install.php) with an installation profile or later by hand.
+   * As a consequence, install-time requirements must be checked without access
+   * to the full Drupal API, because it is not available during install.php.
+   * If a requirement has a severity of REQUIREMENT_ERROR, install.php will abort
+   * or at least the module will not install.
+   * Other severity levels have no effect on the installation.
+   * Module dependencies do not belong to these installation requirements,
+   * but should be defined in the module's .info.yml file.
+   *
+   * During installation, if you need to load a class from your module,
+   * you'll need to include the class file directly.
+   *
+   * @return array
+   *   An associative array where the keys are arbitrary but must be unique (it
+   *   is suggested to use the module short name as a prefix) and the values are
+   *   themselves associative arrays with the following elements:
+   *   - title: The name of the requirement.
+   *   - value: This should only be used for version numbers, do not set it if
+   *     not applicable.
+   *   - description: The description of the requirement/status.
+   *   - severity: (optional) The requirement's result/severity level, one of:
+   *     - REQUIREMENT_INFO: For info only.
+   *     - REQUIREMENT_OK: The requirement is satisfied.
+   *     - REQUIREMENT_WARNING: The requirement failed with a warning.
+   *     - REQUIREMENT_ERROR: The requirement failed with an error.
+   *     Defaults to REQUIREMENT_OK when installing.
+   */
+  public static function getRequirements(): array;
+
+}
diff --git a/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dbbeb86129afafd26968910c40d0753e0837b5d1
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
@@ -0,0 +1,5 @@
+name: 'Test Install Requirements Class'
+type: module
+description: 'Support module for testing install requirements.'
+package: Testing
+version: VERSION
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
new file mode 100644
index 0000000000000000000000000000000000000000..32bc2fef1e02ec273c26e0a8ca018eb320a36853
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\module_install_requirements\Install\Requirements;
+
+use Drupal\Core\Extension\InstallRequirementsInterface;
+
+/**
+ * Provides method for checking requirements during install time.
+ */
+class ModuleInstallRequirements implements InstallRequirementsInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getRequirements(): array {
+    $GLOBALS['module_install_requirements'] = 'module_install_requirements';
+
+    return [];
+  }
+
+}
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml b/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dec6ba7e9e8571db87ee0889749d239627830ae2
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
@@ -0,0 +1,5 @@
+name: 'Test Install Requirements Class'
+type: module
+description: 'Support module for testing install unmet requirements.'
+package: Testing
+version: VERSION
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
new file mode 100644
index 0000000000000000000000000000000000000000..4d7367ff414131aae9cb898e176cf698d4073627
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\module_install_unmet_requirements\Install\Requirements;
+
+use Drupal\Core\Extension\InstallRequirementsInterface;
+
+/**
+ * Provides method for checking requirements during install time.
+ */
+class ModuleInstallUnmetRequirementsRequirements implements InstallRequirementsInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getRequirements(): array {
+    $requirements['testing_requirements'] = [
+      'title' => t('Testing requirements'),
+      'severity' => REQUIREMENT_ERROR,
+      'description' => t('Testing requirements failed requirements.'),
+    ];
+
+    return $requirements;
+  }
+
+}
diff --git a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f6e04e5021c7fe35c2a7f8ad689101814acb0da5
--- /dev/null
+++ b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
@@ -0,0 +1,5 @@
+name: 'Test Install Requirements'
+type: profile
+hidden: true
+description: 'Support profile for testing install requirements.'
+version: VERSION
diff --git a/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php b/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
new file mode 100644
index 0000000000000000000000000000000000000000..9a010b930f7c31d55fc2f9ae9768bb886ca9ec71
--- /dev/null
+++ b/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\profile_install_requirements\Install\Requirements;
+
+use Drupal\Core\Extension\InstallRequirementsInterface;
+
+/**
+ * Provides method for checking requirements during install time.
+ */
+class ProfileInstallRequirementsRequirements implements InstallRequirementsInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getRequirements(): array {
+    $requirements['testing_requirements'] = [
+      'title' => t('Testing requirements'),
+      'severity' => REQUIREMENT_ERROR,
+      'description' => t('Testing requirements failed requirements.'),
+    ];
+
+    return $requirements;
+  }
+
+}
diff --git a/core/tests/Drupal/FunctionalTests/Installer/ProfileRequirementsTest.php b/core/tests/Drupal/FunctionalTests/Installer/ProfileRequirementsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6a6e556944b7015e054c0587345f2ee9a76ffc82
--- /dev/null
+++ b/core/tests/Drupal/FunctionalTests/Installer/ProfileRequirementsTest.php
@@ -0,0 +1,54 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\FunctionalTests\Installer;
+
+/**
+ * Tests installing a profile that implements InstallRequirementsInterface.
+ *
+ * @group Installer
+ */
+class ProfileRequirementsTest extends InstallerTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $profile = 'profile_install_requirements';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpSettings(): void {
+    // This form will never be reached.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpRequirementsProblem(): void {
+    // The parent method asserts that there are no requirements errors, but
+    // this test expects a requirements error in the test method below.
+    // Therefore, we override this method to suppress the parent's assertions.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpSite(): void {
+    // This form will never be reached.
+  }
+
+  /**
+   * Test Requirements are picked up.
+   */
+  public function testRequirementsFailure(): void {
+    $this->assertSession()->pageTextContains('Testing requirements failed requirements.');
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8c05cfd7dc66c159d175dbc64c09515abe838e3d
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\KernelTests\Core\Installer;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests for install requirements.
+ *
+ * @group Installer
+ */
+class InstallRequirementsTest extends KernelTestBase {
+
+  /**
+   * Confirm installer checks requirements in designated classes.
+   */
+  public function testRequirements(): void {
+    require_once 'core/includes/install.inc';
+
+    $this->assertFalse(isset($GLOBALS['module_install_requirements']));
+    drupal_check_module('module_install_requirements');
+    $this->assertTrue(isset($GLOBALS['module_install_requirements']));
+  }
+
+  /**
+   * Tests that the installer returns false if module requirements are not met.
+   */
+  public function testRequirementsFailure(): void {
+    require_once 'core/includes/install.inc';
+    $this->assertFalse(drupal_check_module('module_install_unmet_requirements'));
+  }
+
+}