diff --git a/doc/reference.rst b/doc/reference.rst
index 52cd92bb8812565e71ba4cedf1826bf64633f247..3d78bee36d3e70231fd306344ba2f119529cd494 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -412,6 +412,10 @@ Dealing with Substitution Rules
 
 .. autofunction:: expand_subst
 
+.. autofunction:: find_rules_matching
+
+.. autofunction:: find_one_rule_matching
+
 Caching, Precomputation and Prefetching
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/loopy/__init__.py b/loopy/__init__.py
index 10fac9cfce3eb5a9a1bb6686fabf453ec6b83a8d..d417648b7272aeed5b4a594604ea5eb78024be55 100644
--- a/loopy/__init__.py
+++ b/loopy/__init__.py
@@ -2108,4 +2108,31 @@ def remove_unused_arguments(knl):
 
 # }}}
 
+
+# {{{ find substitution rules by glob patterns
+
+def find_rules_matching(knl, pattern):
+    """
+    :pattern: A shell-style glob pattern.
+    """
+
+    from loopy.context_matching import re_from_glob
+    pattern = re_from_glob(pattern)
+
+    return [r for r in knl.substitutions if pattern.match(r)]
+
+
+def find_one_rule_matching(knl, pattern):
+    rules = find_rules_matching(knl, pattern)
+
+    if len(rules) > 1:
+        raise ValueError("more than one substitution rule matched '%s'"
+                % pattern)
+    if not rules:
+        raise ValueError("no substitution rule matched '%s'" % pattern)
+
+    return rules[0]
+
+# }}}
+
 # vim: foldmethod=marker