diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 66f201c955decbd00119452a505e363d53732f5d..13702c0cebd2cfb06ffc829b444e842237d7c652 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,11 +2,11 @@
 # Uses OWNERS files in different modules throughout the
 # repository as the source of truth for module ownership.
 /** @a11r @nicolasnoble @ctiller
-/binding.gyp @murgatroid99
-/Gemfile @murgatroid99
-/grpc.gemspec @murgatroid99
-/package.json @murgatroid99
-/Rakefile @murgatroid99
+/binding.gyp @murgatroid99 @a11r @nicolasnoble @ctiller
+/Gemfile @murgatroid99 @a11r @nicolasnoble @ctiller
+/grpc.gemspec @murgatroid99 @a11r @nicolasnoble @ctiller
+/package.json @murgatroid99 @a11r @nicolasnoble @ctiller
+/Rakefile @murgatroid99 @a11r @nicolasnoble @ctiller
 /bazel/** @nicolasnoble @dgquintas @ctiller
 /cmake/** @jtattermusch @a11r @nicolasnoble @ctiller
 /doc/PROTOCOL-HTTP2.md @ejona86 @a11r @nicolasnoble @ctiller
diff --git a/tools/mkowners/mkowners.py b/tools/mkowners/mkowners.py
index 18afe3a2f039566782e153d5c06a5fa369633081..4805df45dfcd5d0fa015d526830be1591225815c 100755
--- a/tools/mkowners/mkowners.py
+++ b/tools/mkowners/mkowners.py
@@ -126,30 +126,69 @@ owners_data = new_owners_data
 def full_dir(rules_dir, sub_path):
   return os.path.join(rules_dir, sub_path) if rules_dir != '.' else sub_path
 
-def glob_intersect(g1, g2):
-  if not g2:
-    return all(c == '*' for c in g1)
-  if not g1:
-    return all(c == '*' for c in g2)
-  c1, *t1 = g1
-  c2, *t2 = g2
-  if c1 == '*':
-    return glob_intersect(g1, t2) or glob_intersect(t1, g2)
-  if c2 == '*':
-    return glob_intersect(t1, g2) or glob_intersect(g1, t2)
-  return c1 == c2 and glob_intersect(t1, t2)
+# glob using git
+gg_cache = {}
+def git_glob(glob):
+  global gg_cache
+  if glob in gg_cache: return gg_cache[glob]
+  r = set(subprocess
+      .check_output(['git', 'ls-files', glob])
+      .decode('utf-8')
+      .strip()
+      .splitlines())
+  gg_cache[glob] = r
+  return r
+
+def expand_directives(root, directives):
+  globs = collections.OrderedDict()
+  # build a table of glob --> owners
+  for directive in directives:
+    for glob in directive.globs or ['**']:
+      if glob not in globs:
+        globs[glob] = []
+      if directive.who not in globs[glob]:
+        globs[glob].append(directive.who)
+  # expand owners for intersecting globs
+  sorted_globs = sorted(globs.keys(),
+                        key=lambda g: len(git_glob(os.path.join(root, g))),
+                        reverse=True)
+  out_globs = collections.OrderedDict()
+  for glob_add in sorted_globs:
+    who_add = globs[glob_add]
+    pre_items = [i for i in out_globs.items()]
+    out_globs[glob_add] = who_add.copy()
+    for glob_have, who_have in pre_items:
+      files_add = git_glob(full_dir(root, glob_add))
+      files_have = git_glob(full_dir(root, glob_have))
+      intersect = files_have.intersection(files_add)
+      if intersect:
+        for f in files_add:
+          if f not in intersect:
+            out_globs[os.path.relpath(f, start=root)] = who_add
+        for who in who_have:
+          if who not in out_globs[glob_add]:
+            out_globs[glob_add].append(who)
+  return out_globs
 
 def add_parent_to_globs(parent, globs, globs_dir):
   if not parent: return
   for owners in owners_data:
     if owners.dir == parent:
-      for directive in owners.directives:
-        for dglob in directive.globs or ['**']:
-          for gglob, glob in globs.items():
-            if glob_intersect(full_dir(globs_dir, gglob),
-                              full_dir(owners.dir, dglob)):
-              if directive.who not in glob:
-                glob.append(directive.who)
+      owners_globs = expand_directives(owners.dir, owners.directives)
+      for oglob, oglob_who in owners_globs.items():
+        for gglob, gglob_who in globs.items():
+          files_parent = git_glob(full_dir(owners.dir, oglob))
+          files_child = git_glob(full_dir(globs_dir, gglob))
+          intersect = files_parent.intersection(files_child)
+          gglob_who_orig = gglob_who.copy()
+          if intersect:
+            for f in files_child:
+              if f not in intersect:
+                who = gglob_who_orig.copy()
+                globs[os.path.relpath(f, start=globs_dir)] = who
+            for who in oglob_who:
+              if who not in gglob_who:
+                gglob_who.append(who)
       add_parent_to_globs(owners.parent, globs, globs_dir)
       return
   assert(False)
@@ -165,12 +204,7 @@ with open(args.out, 'w') as out:
     if head.parent and not head.parent in done:
       todo.append(head)
       continue
-    globs = collections.OrderedDict()
-    for directive in head.directives:
-      for glob in directive.globs or ['**']:
-        if glob not in globs:
-          globs[glob] = []
-        globs[glob].append(directive.who)
+    globs = expand_directives(head.dir, head.directives)
     add_parent_to_globs(head.parent, globs, head.dir)
     for glob, owners in globs.items():
       out.write('/%s %s\n' % (