diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/ModifyServiceDefinitionsPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/ModifyServiceDefinitionsPass.php
index 25614e3..8ecded9 100644
--- a/core/lib/Drupal/Core/DependencyInjection/Compiler/ModifyServiceDefinitionsPass.php
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/ModifyServiceDefinitionsPass.php
@@ -28,7 +28,13 @@ public function process(ContainerBuilder $container) {
     if (!($kernel instanceof DrupalKernelInterface)) {
       return;
     }
-    $providers = $kernel->getServiceProviders();
+    $providers = $kernel->getServiceProviders('app');
+    foreach ($providers as $provider) {
+      if ($provider instanceof ServiceModifierInterface) {
+        $provider->alter($container);
+      }
+    }
+    $providers = $kernel->getServiceProviders('site');
     foreach ($providers as $provider) {
       if ($provider instanceof ServiceModifierInterface) {
         $provider->alter($container);
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 8baa101..9603d38 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -110,13 +110,6 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
   protected $configStorage;
 
   /**
-   * The list of the classnames of the service providers in this kernel.
-   *
-   * @var array
-   */
-  protected $serviceProviderClasses;
-
-  /**
    * Whether the container can be dumped.
    *
    * @var bool
@@ -131,14 +124,33 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
   protected $containerNeedsDumping;
 
   /**
-   * Holds the list of YAML files containing service definitions.
+   * List of discovered services.yml pathnames.
+   *
+   * This is a nested array whose top-level keys are 'app' and 'site', denoting
+   * the origin of a service provider. Site-specific providers have to be
+   * collected separately, because they need to be processed last, so as to be
+   * able to override services from application service providers.
    *
    * @var array
    */
   protected $serviceYamls;
 
   /**
-   * The array of registered service providers.
+   * List of discovered service provider class names.
+   *
+   * This is a nested array whose top-level keys are 'app' and 'site', denoting
+   * the origin of a service provider. Site-specific providers have to be
+   * collected separately, because they need to be processed last, so as to be
+   * able to override services from application service providers.
+   *
+   * @var array
+   */
+  protected $serviceProviderClasses;
+
+  /**
+   * List of instantiated service provider classes.
+   *
+   * @see \Drupal\Core\DrupalKernel::$serviceProviderClasses
    *
    * @var array
    */
@@ -203,16 +215,18 @@ public function getContainer() {
    * {@inheritdoc}
    */
   public function discoverServiceProviders() {
-    $serviceProviders = array(
-      'CoreServiceProvider' => new CoreServiceProvider(),
-    );
     $this->serviceYamls = array(
-      'core/core.services.yml'
+      'app' => array(),
+      'site' => array(),
     );
-    $this->serviceProviderClasses = array('Drupal\Core\CoreServiceProvider');
+    $this->serviceProviderClasses = array(
+      'app' => array(),
+      'site' => array(),
+    );
+    $this->serviceYamls['app']['core'] = 'core/core.services.yml';
+    $this->serviceProviderClasses['app']['core'] = 'Drupal\Core\CoreServiceProvider';
 
-    // Ensure we know what modules are enabled and that their namespaces are
-    // registered.
+    // Retrieve enabled modules and register their namespaces.
     if (!isset($this->moduleList)) {
       $extensions = $this->getConfigStorage()->read('core.extension');
       $this->moduleList = isset($extensions['module']) ? $extensions['module'] : array();
@@ -226,34 +240,35 @@ public function discoverServiceProviders() {
       $name = "{$camelized}ServiceProvider";
       $class = "Drupal\\{$module}\\{$name}";
       if (class_exists($class)) {
-        $serviceProviders[$name] = new $class();
-        $this->serviceProviderClasses[] = $class;
+        $this->serviceProviderClasses['app'][$module] = $class;
       }
       $filename = dirname($module_filenames[$module]) . "/$module.services.yml";
       if (file_exists($filename)) {
-        $this->serviceYamls[] = $filename;
+        $this->serviceYamls['app'][$module] = $filename;
       }
     }
 
-    // Add site specific or test service providers.
+    // Add site-specific service providers.
     if (!empty($GLOBALS['conf']['container_service_providers'])) {
-      foreach ($GLOBALS['conf']['container_service_providers'] as $name => $class) {
-        $serviceProviders[$name] = new $class();
-        $this->serviceProviderClasses[] = $class;
+      foreach ($GLOBALS['conf']['container_service_providers'] as $class) {
+        if (class_exists($class)) {
+          $this->serviceProviderClasses['site'][] = $class;
+        }
       }
     }
-    // Add site specific or test YAMLs.
     if (!empty($GLOBALS['conf']['container_yamls'])) {
-      $this->serviceYamls = array_merge($this->serviceYamls, $GLOBALS['conf']['container_yamls']);
+      $this->serviceYamls['site'] = $GLOBALS['conf']['container_yamls'];
+    }
+    if (file_exists($site_services_yml = conf_path() . '/services.yml')) {
+      $this->serviceYamls['site'][] = $site_services_yml;
     }
-    return $serviceProviders;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getServiceProviders() {
-    return $this->serviceProviders;
+  public function getServiceProviders($origin) {
+    return $this->serviceProviders[$origin];
   }
 
   /**
@@ -496,7 +511,6 @@ protected function buildContainer() {
     $this->initializeServiceProviders();
     $container = $this->getContainerBuilder();
     $container->set('kernel', $this);
-    $container->setParameter('container.service_providers', $this->serviceProviderClasses);
     $container->setParameter('container.modules', $this->getModulesParameter());
 
     // Get a list of namespaces and put it onto the container.
@@ -531,11 +545,22 @@ protected function buildContainer() {
     $container->register('class_loader')->setSynthetic(TRUE);
     $container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE);
     $container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE);
+
+    // Register application services.
     $yaml_loader = new YamlFileLoader($container);
-    foreach ($this->serviceYamls as $filename) {
+    foreach ($this->serviceYamls['app'] as $filename) {
+      $yaml_loader->load($filename);
+    }
+    foreach ($this->serviceProviders['app'] as $provider) {
+      if ($provider instanceof ServiceProviderInterface) {
+        $provider->register($container);
+      }
+    }
+    // Register site-specific service overrides.
+    foreach ($this->serviceYamls['site'] as $filename) {
       $yaml_loader->load($filename);
     }
-    foreach ($this->serviceProviders as $provider) {
+    foreach ($this->serviceProviders['site'] as $provider) {
       if ($provider instanceof ServiceProviderInterface) {
         $provider->register($container);
       }
@@ -563,13 +588,15 @@ protected function buildContainer() {
    * @throws \LogicException
    */
   protected function initializeServiceProviders() {
-    $this->serviceProviders = array();
-
-    foreach ($this->discoverServiceProviders() as $name => $provider) {
-      if (isset($this->serviceProviders[$name])) {
-        throw new \LogicException(sprintf('Trying to register two service providers with the same name "%s"', $name));
+    $this->discoverServiceProviders();
+    $this->serviceProviders = array(
+      'app' => array(),
+      'site' => array(),
+    );
+    foreach ($this->serviceProviderClasses as $origin => $classes) {
+      foreach ($classes as $name => $class) {
+        $this->serviceProviders[$origin][$name] = new $class;
       }
-      $this->serviceProviders[$name] = $provider;
     }
   }
 
diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php
index 544b44c..1e2ed07 100644
--- a/core/lib/Drupal/Core/DrupalKernelInterface.php
+++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
@@ -38,10 +38,13 @@ public function discoverServiceProviders();
   /**
    * Returns all registered service providers.
    *
+   * @param string $origin
+   *   The origin for which to return service providers; one of 'app' or 'site'.
+   *
    * @return array
    *   An associative array of ServiceProvider objects, keyed by name.
    */
-  public function getServiceProviders();
+  public function getServiceProviders($origin);
 
   /**
    * Gets the current container.
diff --git a/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelSiteTest.php b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelSiteTest.php
new file mode 100644
index 0000000..d6f9fe8
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/DrupalKernel/DrupalKernelSiteTest.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\DrupalKernel\DrupalKernelSiteTest.
+ */
+
+namespace Drupal\system\Tests\DrupalKernel;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+
+/**
+ * Tests site-specific service overrides.
+ */
+class DrupalKernelSiteTest extends DrupalUnitTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'DrupalKernel site service overrides',
+      'description' => 'Tests site-specific service overrides.',
+      'group' => 'DrupalKernel',
+    );
+  }
+
+  /**
+   * Tests services.yml in site directory.
+   */
+  public function testServicesYml() {
+    $this->assertFalse($this->container->has('site.service.yml'));
+    // A service provider class always has precedence over services.yml files.
+    // DrupalUnitTestBase::buildContainer() swaps out many services with
+    // in-memory implementations already, so those cannot be tested.
+    $this->assertIdentical(get_class($this->container->get('cache.backend.database')), 'Drupal\Core\Cache\DatabaseBackendFactory');
+
+    $class = __CLASS__;
+    $doc = <<<EOD
+services:
+  # Add a new service.
+  site.service.yml:
+    class: $class
+  # Swap out a core service.
+  cache.backend.database:
+    class: Drupal\Core\Cache\MemoryBackendFactory
+EOD;
+    file_put_contents($this->siteDirectory . '/services.yml', $doc);
+
+    // Rebuild the container.
+    $this->kernel->updateModules(array());
+
+    $this->assertTrue($this->container->has('site.service.yml'));
+    $this->assertIdentical(get_class($this->container->get('cache.backend.database')), 'Drupal\Core\Cache\MemoryBackendFactory');
+  }
+
+}
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index b2ce930..8671ca6 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -49,6 +49,11 @@
  *
  * @see example.sites.php
  * @see conf_path()
+ *
+ * In addition to customizing application settings through variables in
+ * settings.php, you can create a services.yml file in the same directory to
+ * register custom, site-specific service definitions and/or swap out default
+ * implementations with custom ones.
  */
 
 /**
