diff --git a/quiz.admin.inc b/quiz.admin.inc
index 0f4707a..186a0af 100644
--- a/quiz.admin.inc
+++ b/quiz.admin.inc
@@ -119,9 +119,9 @@ function quiz_admin_settings($form, &$form_state) {
   $form['quiz_global_settings']['quiz_admin_review_options']['#title'] = t('Administrator review options');
   $form['quiz_global_settings']['quiz_admin_review_options']['#type'] = 'fieldset';
   $form['quiz_global_settings']['quiz_admin_review_options']['#description'] = t('Control what feedback types quiz administrators will see when viewing results for other users.');
-  foreach (array('question' => t('After the question'), 'end' => t('After the @quiz', array('@quiz' => QUIZ_NAME))) as $key => $when) {
+  foreach (quiz_get_feedback_times() as $key => $when) {
     $form['quiz_global_settings']['quiz_admin_review_options']["quiz_admin_review_options_$key"] = array(
-      '#title' => $when,
+      '#title' => $when['name'],
       '#type' => 'checkboxes',
       '#options' => $review_options,
       '#default_value' => variable_get("quiz_admin_review_options_$key", array()),
@@ -1525,3 +1525,16 @@ function theme_quiz_categorized_form($variables) {
     , array('type' => 'inline', 'group' => JS_DEFAULT));
   return $output;
 }
+
+/**
+ * Admin page for feedback settings.
+ */
+function quiz_feedback_page() {
+  $rows = array();
+  $header = array(t('Time'), t('Description'), t('Conditions'));
+  foreach (quiz_get_feedback_times() as $key => $time) {
+    $conditions = l('Conditions', 'admin/quiz/feedback/manage/quiz_feedback_' . $key);
+    $rows[] = array($time['name'], $time['description'], $conditions);
+  }
+  return theme('table', array('caption' => t('Quiz feedback conditions'), 'rows' => $rows, 'header' => $header));
+}
diff --git a/quiz.api.php b/quiz.api.php
index 8e02195..056392b 100644
--- a/quiz.api.php
+++ b/quiz.api.php
@@ -83,3 +83,57 @@ function hook_quiz_question_info() {
     ),
   );
 }
+
+/**
+ * Expose a feedback option to Quiz so that Quiz administrators can choose when
+ * to show it to Quiz takers.
+ *
+ * @return array
+ *   An array of feedback options keyed by machine name.
+ */
+function hook_quiz_feedback_options() {
+  return array(
+    'percentile' => t('Percentile'),
+  );
+}
+
+/**
+ * Allow modules to alter the quiz feedback options.
+ *
+ * @param array $review_options
+ *   An array of review options keyed by a machine name.
+ */
+function hook_quiz_feedback_options_alter(&$review_options) {
+  // Change label.
+  $review_options['quiz_feedback'] = t('General feedback from the Quiz.');
+
+  // Disable showing correct answer.
+  unset($review_options['solution']);
+}
+
+/**
+ * Allow modules to define feedback times.
+ *
+ * Feedback times are configurable by Rules.
+ *
+ * @return array
+ *   An array of feedback times keyed by machine name.
+ */
+function hook_quiz_feedback_times() {
+  return array(
+    '2_weeks_later' => t('Two weeks after finishing'),
+  );
+}
+
+/**
+ * Allow modules to alter the feedback times.
+ *
+ * @param array $feedback_times
+ */
+function hook_quiz_feedback_times_alter(&$feedback_times) {
+  // Change label.
+  $feedback_times['end'] = t('At the end of a quiz');
+
+  // Do not allow question feedback.
+  unset($feedback_times['question']);
+}
diff --git a/quiz.info b/quiz.info
index d6b8ee4..9c8330a 100644
--- a/quiz.info
+++ b/quiz.info
@@ -5,6 +5,7 @@ core = 7.x
 dependencies[] = ctools
 dependencies[] = entity
 dependencies[] = filter
+dependencies[] = rules
 dependencies[] = views
 dependencies[] = views_bulk_operations
 test_dependencies[] = taxonomy
diff --git a/quiz.module b/quiz.module
index ac78a6a..c450b82 100644
--- a/quiz.module
+++ b/quiz.module
@@ -486,6 +486,18 @@ function quiz_menu() {
     );
   }
 
+  $items['admin/quiz/feedback'] = array(
+    'title' => 'Quiz feedback',
+    'description' => 'Configure Quiz feedback behaviors',
+    'page callback' => 'quiz_feedback_page',
+    'access arguments' => array('administer quiz'),
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'quiz.admin.inc',
+  );
+
+  $items += rules_ui()->config_menu('admin/quiz/feedback');
+
+
   return $items;
 }
 
@@ -1148,14 +1160,15 @@ function quiz_form(&$node, &$form_state) {
 
   $review_options = quiz_get_feedback_options();
 
-  foreach (array('question' => t('After the question'), 'end' => t('After the @quiz', array('@quiz' => QUIZ_NAME))) as $key => $when) {
+  foreach (quiz_get_feedback_times() as $key => $when) {
     $form['taking']['review_options'][$key] = array(
-      '#title' => $when,
+      '#title' => $when['name'],
       '#type' => 'checkboxes',
       '#options' => $review_options,
       '#default_value' => isset($node->review_options[$key]) ? $node->review_options[$key] : array(),
     );
   }
+
   $options = array(t('Unlimited'));
   for ($i = 1; $i < 10; $i++) {
     $options[$i] = $i;
@@ -3797,37 +3810,65 @@ function question_number_to_arg() {
  * technically it is the end of the quiz, and the "end of quiz" review settings
  * apply. So we check to make sure that we are in question taking and the
  * feedback is viewed within 5 seconds of completing the question/quiz.
+ *
+ * @param string $option
+ *   An option key
+ * @param QuizResult $quiz_result
+ *   A Quiz result.
+ *
+ * @return bool
+ *   TRUE if the quiz taker can view this quiz option at this time, FALSE
+ *   otherwise.
  */
-function quiz_feedback_can_review($option, $quiz_result) {
+function quiz_feedback_can_review($option, QuizResult $quiz_result) {
   $quiz = node_load($quiz_result->nid, $quiz_result->vid);
 
   $admin = node_access('update', $quiz);
 
   if ($admin) {
+    // Admin user uses the global feedback options.
     $review_options['end'] = variable_get('quiz_admin_review_options_end');
     $review_options['question'] = variable_get('quiz_admin_review_options_question');
   }
   else {
+    // Use this Quiz's feedback options.
     $review_options = $quiz->review_options;
   }
 
-  // Check what context the result is in.
-  if ($quiz_result->time_end && arg(2) != 'take') {
-    // Quiz is over. Pull from the "at quiz end" settings.
-    return !empty($review_options['end'][$option]);
-  }
-
-  if (!$quiz_result->time_end || $quiz_result->time_end >= REQUEST_TIME - 5) {
-    // Quiz ongoing. Pull from the "after question" settings.
-    return !empty($review_options['question'][$option]);
+  $all_shows = array();
+  foreach ($review_options as $time_key => $shows) {
+    // Loop through all the feedback times and check conditions.
+    if ($set = rules_config_load("quiz_feedback_{$time_key}")) {
+      if (!$set->execute($quiz_result)) {
+        // The rule did not pass. Remove the quiz feedback time from eligbility.
+        unset($review_options[$time_key]);
+      }
+      else {
+        // Rules pass so now do something.
+        if ($time_key == 'end') {
+          if ($quiz_result->time_end && arg(2) != 'take') {
+            $all_shows += array_filter($shows);
+          }
+        }
+        else if ($time_key == 'question') {
+          if (!$quiz_result->time_end || $quiz_result->time_end >= REQUEST_TIME - 5) {
+            $all_shows += array_filter($shows);
+          }
+        }
+        else {
+          $all_shows += array_filter($shows);
+        }
+      }
+    }
   }
+  return !empty($all_shows[$option]);
 }
 
 /**
  * Get the feedback options for Quizzes.
  */
 function quiz_get_feedback_options() {
-  $feedback_options = array();
+  $feedback_options = module_invoke_all('quiz_feedback_options');
 
   $entity_info = entity_get_info('node');
   foreach ($entity_info['view modes'] as $view_mode => $info) {
@@ -3853,6 +3894,28 @@ function quiz_get_feedback_options() {
 }
 
 /**
+ * Get the feedback options for Quizzes.
+ */
+function quiz_get_feedback_times() {
+  $feedback_times = array(
+    'question' => array(
+      'name' => t('After the question'),
+      'description' => t('Show feedback after the question'),
+    ),
+    'end' => array(
+      'name' => t('After the quiz'),
+      'description' => t('Show feedback after the quiz'),
+    ),
+  );
+
+  $feedback_times += module_invoke_all('quiz_feedback_times');
+
+  drupal_alter('quiz_feedback_times', $feedback_times);
+
+  return $feedback_times;
+}
+
+/**
  * Check if the question has already been answered in the requested attempt.
  *
  * @return boolean
diff --git a/quiz.rules_defaults.inc b/quiz.rules_defaults.inc
new file mode 100644
index 0000000..907863d
--- /dev/null
+++ b/quiz.rules_defaults.inc
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * Implements hook_default_rules_configuration().
+ */
+function quiz_default_rules_configuration() {
+  $configs = array();
+  foreach (quiz_get_feedback_times() as $key => $when) {
+    $set = rules_and(array(
+      'quiz_result' => array('type' => 'quiz_result', 'label' => t('Quiz attempt')),
+    ));
+    $set->label = t('@title feedback conditions', array('@title' => $when['name']));
+    $set->tags[] = 'quiz';
+
+    $configs["quiz_feedback_$key"] = $set;
+  }
+
+  return $configs;
+}
