diff --git a/Android.bp b/Android.bp
index 8154f48f1dc93d668313d15f8bef0f42cee14b80..26102c907b0a78dc7576840ce70008a0dec99349 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,16 +12,30 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+se_filegroup {
+    name: "26.0.board.compat.map",
+    srcs: [
+        "compat/26.0/26.0.cil",
+    ],
+}
+
+se_filegroup {
+    name: "27.0.board.compat.map",
+    srcs: [
+        "compat/27.0/27.0.cil",
+    ],
+}
+
 se_cil_compat_map {
     name: "26.0.cil",
     srcs: [
-        "private/compat/26.0/26.0.cil",
+        ":26.0.board.compat.map",
     ],
 }
 
 se_cil_compat_map {
     name: "27.0.cil",
     srcs: [
-        "private/compat/27.0/27.0.cil",
+        ":27.0.board.compat.map",
     ],
 }
diff --git a/build/soong/Android.bp b/build/soong/Android.bp
index 0f21be3789f8dc331b7354e2e27c8082dbcc2f5b..bcd33b39f6274389cf4d18913d70fe885b1b280f 100644
--- a/build/soong/Android.bp
+++ b/build/soong/Android.bp
@@ -16,10 +16,14 @@ bootstrap_go_package {
     name: "soong-selinux",
     pkgPath: "android/soong/selinux",
     deps: [
+        "blueprint",
+        "soong",
         "soong-android",
+        "soong-genrule",
     ],
     srcs: [
         "cil_compat_map.go",
+        "filegroup.go"
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/build/soong/cil_compat_map.go b/build/soong/cil_compat_map.go
index 0d91c76788d833f1f2779786cd527bcd362f3cfd..8f557972ca590444af871f12e183b6d2e1a8e804 100644
--- a/build/soong/cil_compat_map.go
+++ b/build/soong/cil_compat_map.go
@@ -54,8 +54,34 @@ type cilCompatMap struct {
 	installSource android.OptionalPath
 }
 
+func expandSeSources(ctx android.ModuleContext, srcFiles []string) android.Paths {
+	expandedSrcFiles := make(android.Paths, 0, len(srcFiles))
+	for _, s := range srcFiles {
+		if m := android.SrcIsModule(s); m != "" {
+			module := ctx.GetDirectDepWithTag(m, android.SourceDepTag)
+			if module == nil {
+				// Error will have been handled by ExtractSourcesDeps
+				continue
+			}
+			if fg, ok := module.(*fileGroup); ok {
+				// Core compatibility mapping files are under system/sepolicy/private.
+				expandedSrcFiles = append(expandedSrcFiles, fg.SystemPrivateSrcs()...)
+				// Partner extensions to the compatibility mapping in must be located in
+				// BOARD_PLAT_PRIVATE_SEPOLICY_DIR
+				expandedSrcFiles = append(expandedSrcFiles, fg.SystemExtPrivateSrcs()...)
+			} else {
+				ctx.ModuleErrorf("srcs dependency %q is not an selinux filegroup", m)
+			}
+		} else {
+			p := android.PathForModuleSrc(ctx, s)
+			expandedSrcFiles = append(expandedSrcFiles, p)
+		}
+	}
+	return expandedSrcFiles
+}
+
 func (c *cilCompatMap) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	srcFiles := ctx.ExpandSources(c.properties.Srcs, nil)
+	srcFiles := expandSeSources(ctx, c.properties.Srcs)
 	for _, src := range srcFiles {
 		if src.Ext() != ".cil" {
 			ctx.PropertyErrorf("srcs", "%s has to be a .cil file.", src.String())
diff --git a/build/soong/filegroup.go b/build/soong/filegroup.go
new file mode 100644
index 0000000000000000000000000000000000000000..744183443e0968978469239c64293f342abcbe23
--- /dev/null
+++ b/build/soong/filegroup.go
@@ -0,0 +1,130 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package selinux
+
+import (
+	"android/soong/android"
+	"path/filepath"
+)
+
+func init() {
+	android.RegisterModuleType("se_filegroup", FileGroupFactory)
+}
+
+func FileGroupFactory() android.Module {
+	module := &fileGroup{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidModule(module)
+	return module
+}
+
+type fileGroupProperties struct {
+	// list of source file suffixes used to collect selinux policy files.
+	// Source files will be looked up in the following local directories:
+	// system/sepolicy/{public, private, vendor, reqd_mask}
+	// and directories specified by following config variables:
+	// BOARD_SEPOLICY_DIRS, BOARD_ODM_SEPOLICY_DIRS
+	// BOARD_PLAT_PUBLIC_SEPOLICY_DIR, BOARD_PLAT_PRIVATE_SEPOLICY_DIR
+	Srcs []string
+}
+
+type fileGroup struct {
+	android.ModuleBase
+	properties fileGroupProperties
+
+	systemPublicSrcs   android.Paths
+	systemPrivateSrcs  android.Paths
+	systemVendorSrcs   android.Paths
+	systemReqdMaskSrcs android.Paths
+
+	systemExtPublicSrcs  android.Paths
+	systemExtPrivateSrcs android.Paths
+
+	vendorSrcs android.Paths
+	odmSrcs    android.Paths
+}
+
+// Source files from system/sepolicy/public
+func (fg *fileGroup) SystemPublicSrcs() android.Paths {
+	return fg.systemPublicSrcs
+}
+
+// Source files from system/sepolicy/private
+func (fg *fileGroup) SystemPrivateSrcs() android.Paths {
+	return fg.systemPrivateSrcs
+}
+
+// Source files from system/sepolicy/vendor
+func (fg *fileGroup) SystemVendorSrcs() android.Paths {
+	return fg.systemVendorSrcs
+}
+
+// Source files from system/sepolicy/reqd_mask
+func (fg *fileGroup) SystemReqdMaskSrcs() android.Paths {
+	return fg.systemReqdMaskSrcs
+}
+
+// Source files from BOARD_PLAT_PUBLIC_SEPOLICY_DIR
+func (fg *fileGroup) SystemExtPublicSrcs() android.Paths {
+	return fg.systemExtPublicSrcs
+}
+
+// Source files from BOARD_PLAT_PRIVATE_SEPOLICY_DIR
+func (fg *fileGroup) SystemExtPrivateSrcs() android.Paths {
+	return fg.systemExtPrivateSrcs
+}
+
+// Source files from BOARD_SEPOLICY_DIRS
+func (fg *fileGroup) VendorSrcs() android.Paths {
+	return fg.vendorSrcs
+}
+
+// Source files from BOARD_ODM_SEPOLICY_DIRS
+func (fg *fileGroup) OdmSrcs() android.Paths {
+	return fg.odmSrcs
+}
+
+func (fg *fileGroup) findSrcsInDirs(ctx android.ModuleContext, dirs []string) android.Paths {
+	result := android.Paths{}
+	for _, f := range fg.properties.Srcs {
+		for _, d := range dirs {
+			path := filepath.Join(d, f)
+			files, _ := ctx.GlobWithDeps(path, nil)
+			for _, f := range files {
+				result = append(result, android.PathForSource(ctx, f))
+			}
+		}
+	}
+	return result
+}
+
+func (fg *fileGroup) findSrcsInDir(ctx android.ModuleContext, dir string) android.Paths {
+	return fg.findSrcsInDirs(ctx, []string{dir})
+}
+
+func (fg *fileGroup) DepsMutator(ctx android.BottomUpMutatorContext) {}
+
+func (fg *fileGroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	fg.systemPublicSrcs = fg.findSrcsInDir(ctx, filepath.Join(ctx.ModuleDir(), "public"))
+	fg.systemPrivateSrcs = fg.findSrcsInDir(ctx, filepath.Join(ctx.ModuleDir(), "private"))
+	fg.systemVendorSrcs = fg.findSrcsInDir(ctx, filepath.Join(ctx.ModuleDir(), "vendor"))
+	fg.systemReqdMaskSrcs = fg.findSrcsInDir(ctx, filepath.Join(ctx.ModuleDir(), "reqd_mask"))
+
+	fg.systemExtPublicSrcs = fg.findSrcsInDir(ctx, ctx.DeviceConfig().PlatPublicSepolicyDir())
+	fg.systemExtPrivateSrcs = fg.findSrcsInDir(ctx, ctx.DeviceConfig().PlatPrivateSepolicyDir())
+
+	fg.vendorSrcs = fg.findSrcsInDirs(ctx, ctx.DeviceConfig().VendorSepolicyDirs())
+	fg.odmSrcs = fg.findSrcsInDirs(ctx, ctx.DeviceConfig().OdmSepolicyDirs())
+}