Index: src/wp-includes/class-wp-theme.php
===================================================================
--- src/wp-includes/class-wp-theme.php	(revision 36349)
+++ src/wp-includes/class-wp-theme.php	(working copy)
@@ -1184,11 +1184,12 @@
 		/**
 		 * Filter the array of themes allowed on the site or network.
 		 *
-		 * @since MU
+		 * @since 4.5.0
 		 *
 		 * @param array $allowed_themes An array of theme stylesheet names.
+		 * @param int   $blog_id        Id of the site or network. Defaults to the current site.
 		 */
-		$network = (array) apply_filters( 'allowed_themes', self::get_allowed_on_network() );
+		$network = (array) apply_filters( 'allowed_themes_combined', self::get_allowed_on_network(), $blog_id );
 		return $network + self::get_allowed_on_site( $blog_id );
 	}
 
@@ -1206,8 +1207,19 @@
 	 */
 	public static function get_allowed_on_network() {
 		static $allowed_themes;
-		if ( ! isset( $allowed_themes ) )
+		if ( ! isset( $allowed_themes ) ) {
 			$allowed_themes = (array) get_site_option( 'allowedthemes' );
+		}
+
+		/**
+		 * Filter the array of themes allowed on the network.
+		 *
+		 * @since MU
+		 *
+		 * @param array $allowed_themes An array of theme stylesheet names.
+		 */
+		$allowed_themes = apply_filters( 'allowed_themes', $allowed_themes );
+
 		return $allowed_themes;
 	}
 
@@ -1230,8 +1242,17 @@
 		if ( ! $blog_id || ! is_multisite() )
 			$blog_id = get_current_blog_id();
 
-		if ( isset( $allowed_themes[ $blog_id ] ) )
-			return $allowed_themes[ $blog_id ];
+		if ( isset( $allowed_themes[ $blog_id ] ) ) {
+			/**
+			 * Filter the array of themes allowed on the site.
+			 *
+			 * @since 4.5.0
+			 *
+			 * @param array $allowed_themes An array of theme stylesheet names.
+			 * @param int   $blog_id        Id of the site. Defaults to current blog.
+			 */
+			return (array) apply_filters( 'allowed_themes_site', $allowed_themes[ $blog_id ], $blog_id );
+		}
 
 		$current = $blog_id == get_current_blog_id();
 
@@ -1279,7 +1300,8 @@
 			}
 		}
 
-		return (array) $allowed_themes[ $blog_id ];
+		/** This filter is documented in wp-includes/class-wp-theme.php */
+		return (array) apply_filters( 'allowed_themes_site', $allowed_themes[ $blog_id ], $blog_id );
 	}
 
 	/**
Index: tests/phpunit/tests/theme/getAllowedFilters.php
===================================================================
--- tests/phpunit/tests/theme/getAllowedFilters.php	(revision 36350)
+++ tests/phpunit/tests/theme/getAllowedFilters.php	(working copy)
@@ -1,8 +1,10 @@
 <?php
+if ( is_multisite() ) :
 /**
  * Tests specific to the filtering of `WP_Theme::get_allowed()` and related functions.
  *
  * @group themes
+ * @group multisite
  */
 class Tests_WP_Theme_Get_Allowed_Filters extends WP_UnitTestCase {
 	/**
@@ -10,6 +12,19 @@
 	 */
 	protected $default_allowed;
 
+	protected $filter_allowed_themes_combined_args;
+
+	public function test_allowed_themes_combined_filter_sends_blog_id() {
+		$blog_id = 1;
+
+		add_filter( 'allowed_themes_combined', array( $this, 'filter_allowed_themes_combined' ), 10, 2 );
+		WP_Theme::get_allowed( $blog_id );
+		remove_filter( 'allowed_themes_combined', array( $this, 'filter_allowed_themes_combined' ) );
+
+		$this->assertEquals( 2, count( $this->filter_allowed_themes_combined_args ) );
+		$this->assertEquals( $blog_id, $this->filter_allowed_themes_combined_args[1] );
+	}
+
 	/**
 	 * Test the `allowed_themes` filter, which filters themes allowed on a network.
 	 */
@@ -27,9 +42,58 @@
 		$this->assertEquals( $expected, $allowed );
 	}
 
+	/**
+	 * Test the `allowed_themes_combined` filter, which filters allowed themes and accepts `$blog_id`.
+	 */
+	public function test_wp_theme_get_allowed_with_allowed_themes_combined_filter() {
+		$blog_id = 1;
+
+		$this->default_allowed = WP_Theme::get_allowed( $blog_id );
+
+		add_filter( 'allowed_themes_combined', array( $this, 'filter_allowed_themes_combined' ), 10, 2 );
+		$allowed = WP_Theme::get_allowed( $blog_id );
+		remove_filter( 'allowed_themes_combined', array( $this, 'filter_allowed_themes_combined' ), 10 );
+
+		$expected = $this->default_allowed + array( 'allowed-themes-combined' => true );
+
+		$this->assertEquals( $expected, $allowed );
+	}
+
+	/**
+	 * Test the `allowed_themes_site` filter, which filters allowed themes for a site.
+	 */
+	public function test_wp_theme_get_allowed_with_allowed_themes_site_filter() {
+		$blog_id = 1;
+
+		$this->default_allowed = WP_Theme::get_allowed( $blog_id );
+
+		add_filter( 'allowed_themes_site', array( $this, 'filter_allowed_themes_site' ), 10, 2 );
+		$allowed = WP_Theme::get_allowed( $blog_id );
+		remove_filter( 'allowed_themes_site', array( $this, 'filter_allowed_themes_site' ), 10 );
+
+		$expected = $this->default_allowed + array( 'allowed-themes-site' => true );
+
+		$this->assertEquals( $expected, $allowed );
+	}
+
 	public function filter_allowed_themes( $allowed_themes ) {
 		$allowed_themes['allow-on-network'] = true;
 
 		return $allowed_themes;
 	}
-}
\ No newline at end of file
+
+	public function filter_allowed_themes_combined( $allowed_themes, $blog_id ) {
+		$this->filter_allowed_themes_combined_args = func_get_args();
+
+		$allowed_themes['allowed-themes-combined'] = true;
+
+		return $allowed_themes;
+	}
+
+	public function filter_allowed_themes_site( $allowed_themes, $blog_id ) {
+		$allowed_themes['allowed-themes-site'] = true;
+
+		return $allowed_themes;
+	}
+}
+endif;
\ No newline at end of file
