diff --git a/src/main/java/org/junit/internal/requests/GlobalRuleRequest.java b/src/main/java/org/junit/internal/requests/GlobalRuleRequest.java
new file mode 100644
index 000000000000..10aa1f0f318e
--- /dev/null
+++ b/src/main/java/org/junit/internal/requests/GlobalRuleRequest.java
@@ -0,0 +1,37 @@
+package org.junit.internal.requests;
+
+import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.GlobalRuleRunner;
+
+/**
+ * A {@link Request} that adds global rules to the {@link Runner}.
+ */
+public final class GlobalRuleRequest extends Request {
+    private final Request request;
+    private final GlobalRuleRunner ruleRunner;
+
+    /**
+     * Creates a Request with global rules
+     *
+     * @param request a {@link Request} describing your Tests
+     * @param ruleRunner {@link GlobalRuleRunner} to apply to the Tests described in
+     * <code>request</code>
+     */
+    public GlobalRuleRequest(Request request, GlobalRuleRunner ruleRunner) {
+        this.request = request;
+        this.ruleRunner = ruleRunner;
+    }
+
+    @Override
+    public Runner getRunner() {
+        try {
+            Runner runner = request.getRunner();
+            ruleRunner.apply(runner);
+            return runner;
+        } catch (Exception e) {
+            return new ErrorReportingRunner(GlobalRuleRunner.class, e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java b/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java
index 338340789ee8..2b5f26e23591 100644
--- a/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java
+++ b/src/main/java/org/junit/runner/JUnitCommandLineParseResult.java
@@ -5,14 +5,17 @@
 import java.util.List;
 
 import org.junit.internal.Classes;
+import org.junit.rules.TestRule;
 import org.junit.runner.FilterFactory.FilterNotCreatedException;
 import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.GlobalRuleRunner;
 import org.junit.runners.model.InitializationError;
 
 class JUnitCommandLineParseResult {
     private final List<String> filterSpecs = new ArrayList<String>();
     private final List<Class<?>> classes = new ArrayList<Class<?>>();
     private final List<Throwable> parserErrors = new ArrayList<Throwable>();
+    private final List<Class<?>> globalRules = new ArrayList<Class<?>>();
 
     /**
      * Do not use. Testing purposes only.
@@ -33,6 +36,13 @@ public List<Class<?>> getClasses() {
         return Collections.unmodifiableList(classes);
     }
 
+    /**
+     * Returns global rules classes parsed from command line.
+     */
+    public List<Class<?>> getGlobalRules() {
+        return Collections.unmodifiableList(globalRules);
+    }
+
     /**
      * Parses the arguments.
      *
@@ -73,6 +83,27 @@ String[] parseOptions(String... args) {
                     }
 
                     filterSpecs.add(filterSpec);
+                } else if (arg.equals("--global-rule")) {
+                    ++i;
+
+                    if (i < args.length) {
+                        try {
+                            Class<?> clazz = Classes.getClass(args[i]);
+
+                            if (TestRule.class.isAssignableFrom(clazz)) {
+                                globalRules.add(clazz);
+                            } else {
+                                parserErrors.add(new CommandLineParserError(args[i] + " does not implement TestRule"));
+                                break;
+                            }
+                        } catch (ClassNotFoundException e) {
+                            parserErrors.add(new CommandLineParserError(args[i] + " is not a valid value for global rule"));
+                            break;
+                        }
+                    } else {
+                        parserErrors.add(new CommandLineParserError(arg + " value not specified"));
+                        break;
+                    }
                 } else {
                     parserErrors.add(new CommandLineParserError("JUnit knows nothing about the " + arg + " option"));
                 }
@@ -115,12 +146,20 @@ public Request createRequest(Computer computer) {
         if (parserErrors.isEmpty()) {
             Request request = Request.classes(
                     computer, classes.toArray(new Class<?>[classes.size()]));
-            return applyFilterSpecs(request);
+            return applyFilterSpecs(applyGlobalRules(request));
         } else {
             return errorReport(new InitializationError(parserErrors));
         }
     }
 
+    private Request applyGlobalRules(Request request) {
+        if (!globalRules.isEmpty()) {
+            return request.withGlobalRules(new GlobalRuleRunner(globalRules));
+        } else {
+            return request;
+        }
+    }
+
     private Request applyFilterSpecs(Request request) {
         try {
             for (String filterSpec : filterSpecs) {
diff --git a/src/main/java/org/junit/runner/Request.java b/src/main/java/org/junit/runner/Request.java
index 264489217f74..474e8a814fb3 100644
--- a/src/main/java/org/junit/runner/Request.java
+++ b/src/main/java/org/junit/runner/Request.java
@@ -5,9 +5,12 @@
 import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
 import org.junit.internal.requests.ClassRequest;
 import org.junit.internal.requests.FilterRequest;
+import org.junit.internal.requests.GlobalRuleRequest;
 import org.junit.internal.requests.SortingRequest;
 import org.junit.internal.runners.ErrorReportingRunner;
+import org.junit.rules.TestRule;
 import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.GlobalRuleRunner;
 import org.junit.runners.model.InitializationError;
 
 /**
@@ -169,4 +172,15 @@ public Request filterWith(Description desiredDescription) {
     public Request sortWith(Comparator<Description> comparator) {
         return new SortingRequest(this, comparator);
     }
+
+    /**
+     * Returns a Request with global {@link TestRule}s that are applied
+     * to every test being run with this Request
+     *
+     * @param ruleRunner The {@link GlobalRuleRunner} to apply to this Request
+     * @return a Request with applied global {@link TestRule}s
+     */
+    public Request withGlobalRules(GlobalRuleRunner ruleRunner) {
+        return new GlobalRuleRequest(this, ruleRunner);
+    }
 }
diff --git a/src/main/java/org/junit/runner/manipulation/GlobalRuleRunnable.java b/src/main/java/org/junit/runner/manipulation/GlobalRuleRunnable.java
new file mode 100644
index 000000000000..c32219d6f3d3
--- /dev/null
+++ b/src/main/java/org/junit/runner/manipulation/GlobalRuleRunnable.java
@@ -0,0 +1,20 @@
+package org.junit.runner.manipulation;
+
+/**
+ * Runners that allow global {@link org.junit.rules.TestRule} should implement this interface.
+ * Implement {@link #setGlobalRules(GlobalRuleRunner)}} to receive the list of classes assignable to
+ * {@link org.junit.rules.TestRule} to apply on every test.
+ *
+ * @since 4.13
+ */
+public interface GlobalRuleRunnable {
+
+    /**
+     * Instantiate and apply global {@link org.junit.rules.TestRule}s to every test.
+     *
+     * @param ruleRunner the {@link GlobalRuleRunner} to apply
+     * @throws Exception if any class does not meet {@link org.junit.runner.Runner}'s requirements
+     */
+    void setGlobalRules(GlobalRuleRunner ruleRunner) throws Exception;
+
+}
diff --git a/src/main/java/org/junit/runner/manipulation/GlobalRuleRunner.java b/src/main/java/org/junit/runner/manipulation/GlobalRuleRunner.java
new file mode 100644
index 000000000000..d833c7ca72a3
--- /dev/null
+++ b/src/main/java/org/junit/runner/manipulation/GlobalRuleRunner.java
@@ -0,0 +1,33 @@
+package org.junit.runner.manipulation;
+
+import java.util.List;
+
+/**
+ * A <code>GlobalRuleRunner</code> passes global {@link org.junit.rules.TestRule}s to the {@link org.junit.runner.Runner}.
+ * In general you will not need to use a <code>GlobalRuleRunner</code> directly. Instead,
+ * use {@link org.junit.runner.Request#withGlobalRules(GlobalRuleRunner)}.
+ *
+ * @since 4.13
+ */
+public class GlobalRuleRunner {
+
+    private final List<Class<?>> rules;
+
+    public GlobalRuleRunner(List<Class<?>> rules) {
+        this.rules = rules;
+    }
+
+    /**
+     * Applies provided global {@link org.junit.rules.TestRule}s to the <code>runner</code>
+     */
+    public void apply(Object object) throws Exception {
+        if (object instanceof GlobalRuleRunnable) {
+            GlobalRuleRunnable runnable = (GlobalRuleRunnable) object;
+            runnable.setGlobalRules(this);
+        }
+    }
+
+    public List<Class<?>> getRules() {
+        return rules;
+    }
+}
diff --git a/src/main/java/org/junit/runners/ParentRunner.java b/src/main/java/org/junit/runners/ParentRunner.java
index 4949c242e5b2..b77b928c6315 100644
--- a/src/main/java/org/junit/runners/ParentRunner.java
+++ b/src/main/java/org/junit/runners/ParentRunner.java
@@ -5,6 +5,7 @@
 import static org.junit.internal.runners.rules.RuleMemberValidator.CLASS_RULE_VALIDATOR;
 
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -16,11 +17,7 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Ignore;
-import org.junit.Rule;
+import org.junit.*;
 import org.junit.internal.AssumptionViolatedException;
 import org.junit.internal.runners.model.EachTestNotifier;
 import org.junit.internal.runners.statements.RunAfters;
@@ -29,11 +26,7 @@
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runner.Runner;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runner.manipulation.Filterable;
-import org.junit.runner.manipulation.NoTestsRemainException;
-import org.junit.runner.manipulation.Sortable;
-import org.junit.runner.manipulation.Sorter;
+import org.junit.runner.manipulation.*;
 import org.junit.runner.notification.RunNotifier;
 import org.junit.runner.notification.StoppedByUserException;
 import org.junit.runners.model.FrameworkMember;
@@ -55,13 +48,13 @@
  * must implement finding the children of the node, describing each child, and
  * running each child. ParentRunner will filter and sort children, handle
  * {@code @BeforeClass} and {@code @AfterClass} methods,
- * handle annotated {@link ClassRule}s, create a composite
- * {@link Description}, and run children sequentially.
+ * handle annotated {@link ClassRule}s, handle provided global {@link TestRule}s,
+ * create a composite {@link Description}, and run children sequentially.
  *
  * @since 4.5
  */
 public abstract class ParentRunner<T> extends Runner implements Filterable,
-        Sortable {
+        Sortable, GlobalRuleRunnable {
     private static final List<TestClassValidator> VALIDATORS = Arrays.<TestClassValidator>asList(
             new AnnotationsValidator());
 
@@ -71,6 +64,8 @@ public abstract class ParentRunner<T> extends Runner implements Filterable,
     // Guarded by childrenLock
     private volatile Collection<T> filteredChildren = null;
 
+    private List<TestRule> globalRules = new ArrayList<TestRule>();
+
     private volatile RunnerScheduler scheduler = new RunnerScheduler() {
         public void schedule(Runnable childStatement) {
             childStatement.run();
@@ -192,6 +187,7 @@ private void validateClassRules(List<Throwable> errors) {
      * construct a statement that will:
      * <ol>
      * <li>Apply all {@code ClassRule}s on the test-class and superclasses.</li>
+     * <li>Apply all global {@code TestRule}s on the test-class and superclasses.</li>
      * <li>Run all non-overridden {@code @BeforeClass} methods on the test-class
      * and superclasses; if any throws an Exception, stop execution and pass the
      * exception on.</li>
@@ -212,6 +208,7 @@ protected Statement classBlock(final RunNotifier notifier) {
             statement = withBeforeClasses(statement);
             statement = withAfterClasses(statement);
             statement = withClassRules(statement);
+            statement = withGlobalRules(statement);
         }
         return statement;
     }
@@ -266,6 +263,20 @@ private Statement withClassRules(Statement statement) {
                 new RunRules(statement, classRules, getDescription());
     }
 
+    /**
+     * Returns a {@link Statement}: apply all
+     * classes assignable to {@link TestRule} provided
+     * by command line argument {@code --global-rule}.
+     *
+     * @param statement the base statement
+     * @return a RunRules statement if any global-level {@link TestRule}s are
+     *         provided, or the base statement
+     */
+    private Statement withGlobalRules(Statement statement) {
+        return globalRules.isEmpty() ? statement :
+                new RunRules(statement, globalRules, getDescription());
+    }
+
     /**
      * @return the {@code ClassRule}s that can transform the block that runs
      *         each method in the tested class.
@@ -403,7 +414,7 @@ public void run(final RunNotifier notifier) {
     }
 
     //
-    // Implementation of Filterable and Sortable
+    // Implementation of Filterable, Sortable and GlobalRuleRunnable
     //
 
     public void filter(Filter filter) throws NoTestsRemainException {
@@ -445,6 +456,29 @@ public void sort(Sorter sorter) {
         }
     }
 
+    public void setGlobalRules(GlobalRuleRunner rules) throws Exception {
+        childrenLock.lock();
+        try {
+            for (T each : getFilteredChildren()) {
+                rules.apply(each);
+            }
+            for (Class<?> clazz : rules.getRules()) {
+                Constructor<?>[] constructors = clazz.getConstructors();
+                if (constructors.length > 1) {
+                    throw new IllegalArgumentException("Global TestRule can only have one constructor");
+                }
+                Assert.assertEquals(1, constructors.length);
+                Constructor<?> constructor = clazz.getConstructors()[0];
+                if (constructor.getParameterTypes().length > 0) {
+                    throw new IllegalArgumentException("Global TestRule constructor cannot have parameters");
+                }
+                globalRules.add(TestRule.class.cast(constructor.newInstance()));
+            }
+        } finally {
+            childrenLock.unlock();
+        }
+    }
+
     //
     // Private implementation
     //
diff --git a/src/test/java/org/junit/rules/AllRulesTests.java b/src/test/java/org/junit/rules/AllRulesTests.java
index 8b63e1510db3..efe356fd4195 100644
--- a/src/test/java/org/junit/rules/AllRulesTests.java
+++ b/src/test/java/org/junit/rules/AllRulesTests.java
@@ -8,6 +8,7 @@
 @SuiteClasses({
         BlockJUnit4ClassRunnerOverrideTest.class,
         ClassRulesTest.class,
+        GlobalRulesTest.class,
         DisableOnDebugTest.class,
         ErrorCollectorTest.class,
         ExpectedExceptionTest.class,
diff --git a/src/test/java/org/junit/rules/GlobalRulesTest.java b/src/test/java/org/junit/rules/GlobalRulesTest.java
new file mode 100644
index 000000000000..46de1bc9a131
--- /dev/null
+++ b/src/test/java/org/junit/rules/GlobalRulesTest.java
@@ -0,0 +1,60 @@
+package org.junit.rules;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.manipulation.GlobalRuleRunner;
+import org.junit.runners.model.Statement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests to exercise global-level rules.
+ */
+public class GlobalRulesTest {
+    private static int count = 0;
+
+    public static class Counter implements TestRule {
+        public Statement apply(Statement base, Description description) {
+            count++;
+            return base;
+        }
+    }
+
+    public static class ExampleTest {
+        @Test
+        public void firstTest() {
+            assertEquals(2, count);
+        }
+
+        @Test
+        public void secondTest() {
+            assertEquals(2, count);
+        }
+    }
+
+    public static class SecondExampleTest {
+        @Test
+        public void firstTest() {
+            assertEquals(3, count);
+        }
+
+        @Test
+        public void secondTest() {
+            assertEquals(3, count);
+        }
+    }
+
+    @Test
+    public void rulesAreAppliedOnEveryTest() {
+        List<Class<?>> rules = new ArrayList<Class<?>>();
+        rules.add(Counter.class);
+        new JUnitCore().run(Request.classes(ExampleTest.class, SecondExampleTest.class)
+                .withGlobalRules(new GlobalRuleRunner(rules)));
+        assertEquals(3, count);
+    }
+}
diff --git a/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java b/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java
index ffd1f1c9552f..e76d532b3770 100644
--- a/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java
+++ b/src/test/java/org/junit/runner/JUnitCommandLineParseResultTest.java
@@ -11,7 +11,9 @@
 import org.junit.Test;
 import org.junit.experimental.categories.IncludeCategories;
 import org.junit.rules.ExpectedException;
+import org.junit.rules.TestRule;
 import org.junit.runner.manipulation.Filter;
+import org.junit.runners.model.Statement;
 
 public class JUnitCommandLineParseResultTest {
     @Rule
@@ -47,6 +49,16 @@ public void shouldCreateFailureUponBaldFilterOptionNotFollowedByValue() {
         assertThat(description.toString(), containsString("initializationError"));
     }
 
+    @Test
+    public void shouldCreateFailureUponBaldGlobalRuleOptionNotFollowedByValue() {
+        jUnitCommandLineParseResult.parseOptions("--global-rule");
+
+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();
+        Description description = runner.getDescription().getChildren().get(0);
+
+        assertThat(description.toString(), containsString("initializationError"));
+    }
+
     @Test
     public void shouldParseFilterArgInWhichValueIsASeparateArg() throws Exception {
         String value= IncludeCategories.class.getName() + "=" + DummyCategory0.class.getName();
@@ -116,6 +128,19 @@ public void shouldAddToClasses() {
         assertThat(testClass.getName(), is(DummyTest.class.getName()));
     }
 
+    @Test
+    public void shouldAddToGlobalRules() {
+        jUnitCommandLineParseResult.parseOptions(new String[]{
+                "--global-rule",
+                DummyRule.class.getName()
+        });
+
+        List<Class<?>> classes = jUnitCommandLineParseResult.getGlobalRules();
+        Class<?> ruleClass = classes.get(0);
+
+        assertThat(ruleClass.getName(), is(DummyRule.class.getName()));
+    }
+
     @Test
     public void shouldCreateFailureUponUnknownTestClass() throws Exception {
         String unknownTestClass = "UnknownTestClass";
@@ -129,6 +154,33 @@ public void shouldCreateFailureUponUnknownTestClass() throws Exception {
         assertThat(description.toString(), containsString("initializationError"));
     }
 
+    @Test
+    public void shouldCreateFailureUponUnknownGlobalRule() throws Exception {
+        String unknownRuleClass = "UnknownRuleClass";
+        jUnitCommandLineParseResult.parseOptions(new String[]{
+                "--global-rule",
+                unknownRuleClass
+        });
+
+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();
+        Description description = runner.getDescription().getChildren().get(0);
+
+        assertThat(description.toString(), containsString("initializationError"));
+    }
+
+    @Test
+    public void shouldCreateFailureUponNonAssignableToTestRuleGlobalRule() throws Exception {
+        jUnitCommandLineParseResult.parseOptions(new String[]{
+                "--global-rule",
+                DummyTest.class.getName()
+        });
+
+        Runner runner = jUnitCommandLineParseResult.createRequest(new Computer()).getRunner();
+        Description description = runner.getDescription().getChildren().get(0);
+
+        assertThat(description.toString(), containsString("initializationError"));
+    }
+
     public static class FilterFactoryStub implements FilterFactory {
         public Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException {
             throw new FilterNotCreatedException(new Exception("stub"));
@@ -143,4 +195,10 @@ public static class DummyTest {
         public void dummyTest() {
         }
     }
+
+    public static class DummyRule implements TestRule {
+        public Statement apply(Statement base, Description description) {
+            return base;
+        }
+    }
 }