diff --git a/includes/form.inc b/includes/form.inc
index 60b870709d6..60b39a86431 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -126,8 +126,10 @@ function drupal_get_form($form_id) {
  *     common elements, such as back/next/save buttons in multi-step form
  *     wizards, may define a form builder function name that returns a form
  *     structure, which is passed on to the actual form builder function.
- *     Such forms cannot use drupal_get_form() and need to prepare $form_state
- *     on their own.
+ *     Such implementations may either define the 'wrapper_callback' via
+ *     hook_forms() or have to invoke drupal_build_form() (instead of
+ *     drupal_get_form()) on their own in a custom menu callback to prepare
+ *     $form_state accordingly.
  *   Further $form_state properties controlling the redirection behavior after
  *   form submission may be found in drupal_redirect_form().
  *
@@ -479,8 +481,19 @@ function drupal_retrieve_form($form_id, &$form_state) {
     if (isset($form_definition['callback'])) {
       $callback = $form_definition['callback'];
     }
+    // In case $form_state['wrapper_callback'] is not defined already, we also
+    // allow hook_forms() to define one.
+    if (!isset($form_state['wrapper_callback']) && isset($form_definition['wrapper_callback'])) {
+      $form_state['wrapper_callback'] = $form_definition['wrapper_callback'];
+    }
   }
 
+  $form = array();
+  // We need to pass $form_state by reference in order for forms to modify it,
+  // since call_user_func_array() requires that referenced variables are passed
+  // explicitly.
+  $args = array_merge(array($form, &$form_state), $args);
+
   // When the passed $form_state (not using drupal_get_form()) defines a
   // 'wrapper_callback', then it requests to invoke a separate (wrapping) form
   // builder function to pre-populate the $form array with form elements, which
@@ -488,14 +501,11 @@ function drupal_retrieve_form($form_id, &$form_state) {
   // pre-populating a form with common elements for certain forms, such as
   // back/next/save buttons in multi-step form wizards.
   // @see drupal_build_form()
-  $form = array();
   if (isset($form_state['wrapper_callback']) && function_exists($form_state['wrapper_callback'])) {
-    $form = $form_state['wrapper_callback']($form, $form_state);
+    $form = call_user_func_array($form_state['wrapper_callback'], $args);
+    // Put the prepopulated $form into $args.
+    $args[0] = $form;
   }
-  // We need to pass $form_state by reference in order for forms to modify it,
-  // since call_user_func_array() requires that referenced variables be passed
-  // explicitly.
-  $args = array_merge(array($form, &$form_state), $args);
 
   // If $callback was returned by a hook_forms() implementation, call it.
   // Otherwise, call the function named after the form id.
diff --git a/modules/color/color.module b/modules/color/color.module
index 882d23cba82..7f6f47b31ff 100644
--- a/modules/color/color.module
+++ b/modules/color/color.module
@@ -139,8 +139,7 @@ function color_get_palette($theme, $default = FALSE) {
 /**
  * Form callback. Returns the configuration form.
  */
-function color_scheme_form($form, &$form_state, $theme) {
-  $form = array();
+function color_scheme_form($complete_form, &$form_state, $theme) {
   $base = drupal_get_path('module', 'color');
   $info = color_get_info($theme);
 
diff --git a/modules/node/node.module b/modules/node/node.module
index 735fc30c4c9..67990084c44 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1480,7 +1480,6 @@ function node_search_status() {
  * Implement hook_search_admin().
  */
 function node_search_admin() {
-  $form = array();
   // Output form for defining rank factor weights.
   $form['content_ranking'] = array(
     '#type' => 'fieldset',
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index f0302ff47bd..c1271c45961 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -321,13 +321,10 @@ class FormsElementsTableSelectFunctionalTest extends DrupalWebTestCase {
    * @return
    *   An array containing the processed form, the form_state and any errors.
    */
-  private function formSubmitHelper($form_element, $edit) {
+  private function formSubmitHelper($form, $edit) {
     $form_id = $this->randomName();
-
     $form_state = form_state_defaults();
-    $form = array();
 
-    $form = array_merge($form, $form_element);
     $form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
 
     $form_state['input'] = $edit;
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index 339f82d04ea..327f6c56965 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -645,9 +645,11 @@ function hook_form_system_theme_settings_alter(&$form, &$form_state) {
  * function but each form will have a different form id for submission,
  * validation, theming or alteration by other modules.
  *
- * The callback arguments will be passed as parameters to the function. Callers
- * of drupal_get_form() are also able to pass in parameters. These will be
- * appended after those specified by hook_forms().
+ * The 'callback arguments' will be passed as parameters to the function defined
+ * in 'callback'. In case the code that calls drupal_get_form() also passes
+ * parameters, then the 'callback' function will receive the
+ * 'callback arguments' specified in hook_forms() before those that have been
+ * passed to drupal_get_form().
  *
  * See node_forms() for an actual example of how multiple forms share a common
  * building function.
@@ -656,16 +658,44 @@ function hook_form_system_theme_settings_alter(&$form, &$form_state) {
  *   The unique string identifying the desired form.
  * @param $args
  *   An array containing the original arguments provided to drupal_get_form().
+ *   These are always passed to the form builder and do not have to be specified
+ *   manually in 'callback arguments'.
+ *
  * @return
- *   An array keyed by form_id with callbacks and optional, callback arguments.
+ *   An associative array whose keys define form_ids and whose values are an
+ *   associative array defining the following keys:
+ *   - callback: The name of the form builder function to invoke.
+ *   - callback arguments: (optional) Additional arguments to pass to the
+ *     function defined in 'callback', which are prepended to $args.
+ *   - wrapper_callback: (optional) The name of a form builder function to
+ *     invoke before the form builder defined in 'callback' is invoked. This
+ *     wrapper callback may prepopulate the $form array with form elements,
+ *     which will then be already contained in the $form that is passed on to
+ *     the form builder defined in 'callback'. For example, a wrapper callback
+ *     could setup wizard-alike form buttons that are the same for a variety of
+ *     forms that belong to the wizard, which all share the same wrapper
+ *     callback.
  */
 function hook_forms($form_id, $args) {
+  // Simply reroute the (non-existing) $form_id 'mymodule_first_form' to
+  // 'mymodule_main_form'.
   $forms['mymodule_first_form'] = array(
-    'callback' => 'mymodule_form_builder',
+    'callback' => 'mymodule_main_form',
+  );
+
+  // Reroute the $form_id and prepend an additional argument that gets passed to
+  // the 'mymodule_main_form' form builder function.
+  $forms['mymodule_second_form'] = array(
+    'callback' => 'mymodule_main_form',
     'callback arguments' => array('some parameter'),
   );
-  $forms['mymodule_second_form'] = array(
-    'callback' => 'mymodule_form_builder',
+
+  // Reroute the $form_id, but invoke the form builder function
+  // 'mymodule_main_form_wrapper' first, so we can prepopulate the $form array
+  // that is passed to the actual form builder 'mymodule_main_form'.
+  $forms['mymodule_wrapped_form'] = array(
+    'callback' => 'mymodule_main_form',
+    'wrapper_callback' => 'mymodule_main_form_wrapper',
   );
 
   return $forms;
diff --git a/update.php b/update.php
index 2d4f1e50ed8..e9e5c84f6ac 100644
--- a/update.php
+++ b/update.php
@@ -37,8 +37,7 @@ function update_selection_page() {
   return $output;
 }
 
-function update_script_selection_form() {
-  $form = array();
+function update_script_selection_form($form, &$form_state) {
   $count = 0;
   $form['start'] = array(
     '#tree' => TRUE,